Miscellaneous utilities on ordinary Haskell syntax used by the arrow translator.
> module Utils(
>	FreeVars(freeVars), DefinedVars(definedVars),
>	failureFree, irrPat, paren, parenInfixArg,
>	tuple, tupleP,
>	times
> ) where
> import Data.Set (Set)
> import qualified Data.Set as Set
> import Language.Haskell.Syntax
The set of free variables in some construct.
> class FreeVars a where
>	freeVars :: a -> Set HsName
> instance FreeVars a => FreeVars [a] where
>	freeVars = Set.unions . map freeVars
> instance FreeVars HsPat where
>	freeVars (HsPVar n) = Set.singleton n
>	freeVars (HsPLit _) = Set.empty
>	freeVars (HsPNeg p) = freeVars p
>	freeVars (HsPInfixApp p1 _ p2) = freeVars p1 `Set.union` freeVars p2
>	freeVars (HsPApp _ ps) = freeVars ps
>	freeVars (HsPTuple ps) = freeVars ps
>	freeVars (HsPList ps) = freeVars ps
>	freeVars (HsPParen p) = freeVars p
>	freeVars (HsPRec _ pfs) = freeVars pfs
>	freeVars (HsPAsPat n p) = Set.insert n (freeVars p)
>	freeVars (HsPWildCard) = Set.empty
>	freeVars (HsPIrrPat p) = freeVars p
> instance FreeVars HsPatField where
>	freeVars (HsPFieldPat _ p) = freeVars p
> instance FreeVars HsFieldUpdate where
>	freeVars (HsFieldUpdate _ e) = freeVars e
> instance FreeVars HsExp where
>	freeVars (HsVar n) = freeVars n
>	freeVars (HsCon _) = Set.empty
>	freeVars (HsLit _) = Set.empty
>	freeVars (HsInfixApp e1 op e2) =
>		freeVars e1 `Set.union` freeVars op `Set.union` freeVars e2
>	freeVars (HsApp f e) = freeVars f `Set.union` freeVars e
>	freeVars (HsNegApp e) = freeVars e
>	freeVars (HsLambda _ ps e) = freeVars e `Set.difference` freeVars ps
>	freeVars (HsLet decls e) =
>		(freeVars decls `Set.union` freeVars e) `Set.difference`
>			definedVars decls
>	freeVars (HsIf e1 e2 e3) =
>		freeVars e1 `Set.union` freeVars e2 `Set.union` freeVars e3
>	freeVars (HsCase e as) = freeVars e `Set.union` freeVars as
>	freeVars (HsDo ss) = freeVarsStmts ss
>	freeVars (HsTuple es) = freeVars es
>	freeVars (HsList es) = freeVars es
>	freeVars (HsParen e) = freeVars e
>	freeVars (HsLeftSection e op) = freeVars e `Set.union` freeVars op
>	freeVars (HsRightSection op e) = freeVars op `Set.union` freeVars e
>	freeVars (HsRecConstr _ us) = freeVars us
>	freeVars (HsRecUpdate e us) = freeVars e `Set.union` freeVars us
>	freeVars (HsEnumFrom e) = freeVars e
>	freeVars (HsEnumFromTo e1 e2) = freeVars e1 `Set.union` freeVars e2
>	freeVars (HsEnumFromThen e1 e2) = freeVars e1 `Set.union` freeVars e2
>	freeVars (HsEnumFromThenTo e1 e2 e3) =
>		freeVars e1 `Set.union` freeVars e2 `Set.union` freeVars e3
>	freeVars (HsListComp e ss) =
>		freeVars e `Set.union` freeVarsStmts ss
>	freeVars (HsExpTypeSig _ e _) = freeVars e
>	freeVars (HsAsPat _ _) = error "freeVars (x @ p)"
>	freeVars (HsWildCard) = error "freeVars _"
>	freeVars (HsIrrPat _) = error "freeVars ~p"
> instance FreeVars HsQOp where
>	freeVars (HsQVarOp n) = freeVars n
>	freeVars (HsQConOp _) = Set.empty
> instance FreeVars HsQName where
>	freeVars (UnQual v) = Set.singleton v
>	freeVars _ = Set.empty
> instance FreeVars HsAlt where
>	freeVars (HsAlt _ p gas decls) =
>		(freeVars gas `Set.union` freeVars decls) `Set.difference`
>		(freeVars p `Set.union` definedVars decls)
> instance FreeVars HsGuardedAlts where
>	freeVars (HsUnGuardedAlt e) = freeVars e
>	freeVars (HsGuardedAlts alts) = freeVars alts
> instance FreeVars HsGuardedAlt where
>	freeVars (HsGuardedAlt _ e1 e2) = freeVars e1 `Set.union` freeVars e2
> instance FreeVars HsDecl where
>	freeVars (HsFunBind ms) = freeVars ms
>	freeVars (HsPatBind _ p rhs decls) =
>		(freeVars rhs `Set.union` freeVars decls) `Set.difference`
>		(freeVars p `Set.union` definedVars decls)
>	freeVars _ = Set.empty
> instance FreeVars HsMatch where
>	freeVars (HsMatch _ n ps rhs decls) =
>		(freeVars rhs `Set.union` freeVars decls) `Set.difference`
>		(Set.insert n (freeVars ps) `Set.union` definedVars decls)
> instance FreeVars HsRhs where
>	freeVars (HsUnGuardedRhs e) = freeVars e
>	freeVars (HsGuardedRhss grs) = freeVars grs
> instance FreeVars HsGuardedRhs where
>	freeVars (HsGuardedRhs _ e1 e2) = freeVars e1 `Set.union` freeVars e2
> freeVarsStmts :: [HsStmt] -> Set HsName
> freeVarsStmts = foldr addStmt Set.empty
>	where	addStmt (HsGenerator _ p e) s =
>			freeVars e `Set.union` (s `Set.difference` freeVars p)
>		addStmt (HsQualifier e) _s = freeVars e
>		addStmt (HsLetStmt decls) s =
>			(freeVars decls `Set.union` s) `Set.difference` definedVars decls
The set of variables defined by a construct.
> class DefinedVars a where
>	definedVars :: a -> Set HsName
> instance DefinedVars a => DefinedVars [a] where
>	definedVars = Set.unions . map definedVars
> instance DefinedVars HsDecl where
>	definedVars (HsFunBind (HsMatch _ n _ _ _:_)) = Set.singleton n
>	definedVars (HsPatBind _ p _ _) = freeVars p
>	definedVars _ = Set.empty
Is the pattern failure-free? (This is incomplete at the moment, because patterns made with unique constructors should be failure-free, but we have no way of detecting them.)
> failureFree :: HsPat -> Bool
> failureFree (HsPVar _) = True
> failureFree (HsPApp n ps) = n == unit_con_name && null ps
> failureFree (HsPTuple ps) = all failureFree ps
> failureFree (HsPParen p) = failureFree p
> failureFree (HsPAsPat _ p) = failureFree p
> failureFree (HsPWildCard) = True
> failureFree (HsPIrrPat _) = True
> failureFree _ = False
Irrefutable version of a pattern
> irrPat :: HsPat -> HsPat
> irrPat p@(HsPVar _) = p
> irrPat (HsPParen p) = HsPParen (irrPat p)
> irrPat (HsPAsPat n p) = HsPAsPat n (irrPat p)
> irrPat p@(HsPWildCard) = p
> irrPat p@(HsPIrrPat _) = p
> irrPat p = HsPIrrPat p
Make an expression into an aexp, by adding parentheses if required.
> paren :: HsExp -> HsExp
> paren e = if isAexp e then e else HsParen e
>	where	isAexp (HsVar _) = True
>		isAexp (HsCon _) = True
>		isAexp (HsLit _) = True
>		isAexp (HsParen _) = True
>		isAexp (HsTuple _) = True
>		isAexp (HsList _) = True
>		isAexp (HsEnumFrom _) = True
>		isAexp (HsEnumFromTo _ _) = True
>		isAexp (HsEnumFromThen _ _) = True
>		isAexp (HsEnumFromThenTo _ _ _) = True
>		isAexp (HsListComp _ _) = True
>		isAexp (HsLeftSection _ _) = True
>		isAexp (HsRightSection _ _) = True
>		isAexp (HsRecConstr _ _) = True
>		isAexp (HsRecUpdate _ _) = True
>		isAexp _ = False
Make an expression into an fexp, by adding parentheses if required.
> parenInfixArg :: HsExp -> HsExp
> parenInfixArg e@(HsApp _ _) = e
> parenInfixArg e = paren e
Tuples
> tuple :: [HsExp] -> HsExp
> tuple [] = unit_con
> tuple [e] = e
> tuple es = HsTuple es
> tupleP :: [HsPat] -> HsPat
> tupleP [] = HsPApp unit_con_name []
> tupleP [e] = e
> tupleP es = HsPTuple es
Compose a function n times.
> times :: Int -> (a -> a) -> a -> a
> times n f a = foldr ($) a (replicate n f)