> module ArrCode(
> Arrow,
> bind, anon,
> arr, arrLet, (>>>), arrowExp, applyOp, infixOp, (|||), first,
> VarDecl(VarDecl), letCmd,
> context, anonArgs, toHaskell,
> Tuple(..),
> isEmptyTuple, unionTuple, minusTuple, intersectTuple,
> patternTuple, expTuple,
> returnA_exp, arr_exp, compose_op, choice_op, first_exp,
> left_exp, right_exp, app_exp, loop_exp,
> ifte
> ) where
> import Utils
> import Data.Set (Set)
> import qualified Data.Set as Set
> import Language.Haskell.Syntax
> data Arrow = Arrow {
> code :: Code,
> context :: Tuple,
> anonArgs :: Int
> }
> data VarDecl a = VarDecl SrcLoc HsName a
> deriving (Eq,Show)
> instance Functor VarDecl where
> fmap f (VarDecl loc name a) = VarDecl loc name (f a)
> data Code
> = ReturnA
> | Arr Int HsPat [Binding] HsExp
> | Compose Code [Code] Code
> | Op HsExp [Code]
> | InfixOp Code HsQOp Code
> | Let [VarDecl Code] Code
> | Ifte HsExp Code Code
> data Binding = BindLet [HsDecl] | BindCase HsPat HsExp
-----------------------------------------------------------------------------
Arrow constants
> compose_op, choice_op :: HsQOp
> returnA_exp, arr_exp, first_exp :: HsExp
> left_exp, right_exp, app_exp, loop_exp :: HsExp
> returnA_exp = HsVar (UnQual (HsIdent "returnA"))
> arr_exp = HsVar (UnQual (HsIdent "arr"))
> compose_op = HsQVarOp (UnQual (HsSymbol ">>>"))
> choice_op = HsQVarOp (UnQual (HsSymbol "|||"))
> first_exp = HsVar (UnQual (HsIdent "first"))
> left_exp = HsCon (UnQual (HsIdent "Left"))
> right_exp = HsCon (UnQual (HsIdent "Right"))
> app_exp = HsVar (UnQual (HsIdent "app"))
> loop_exp = HsVar (UnQual (HsIdent "loop"))
-----------------------------------------------------------------------------
Arrow constructors
> bind :: Set HsName -> Arrow -> Arrow
> bind vars a = a {
> context = context a `minusTuple` vars
> }
> anon :: Int -> Arrow -> Arrow
> anon anonCount a = a {
> anonArgs = anonArgs a + anonCount
> }
> arr :: Int -> Tuple -> HsPat -> HsExp -> Arrow
> arr anons t p e = Arrow {
> code = if same p e then ReturnA else Arr anons p [] e,
> context = t `intersectTuple` freeVars e,
> anonArgs = anons
> }
> where same :: HsPat -> HsExp -> Bool
> same (HsPApp n1 []) (HsCon n2) = n1 == n2
> same (HsPVar n1) (HsVar n2) = UnQual n1 == n2
> same (HsPTuple ps) (HsTuple es) =
> length ps == length es && and (zipWith same ps es)
> same (HsPAsPat n p) e = e == HsVar (UnQual n) || same p e
> same (HsPParen p) e = same p e
> same p (HsParen e) = same p e
> same _ _ = False
> arrLet :: Int -> Tuple -> HsPat -> [HsDecl] -> HsExp -> Arrow
> arrLet anons t p ds e = Arrow {
> code = Arr anons p [BindLet ds] e,
> context = t `intersectTuple` vs,
> anonArgs = anons
> }
> where vs = (freeVars e `Set.union` freeVars ds)
> `Set.difference` definedVars ds
> ifte :: HsExp -> Arrow -> Arrow -> Arrow
> ifte c th el = Arrow
> { code = Ifte c (code th) (code el)
> , context = context th `unionTuple` context el
> , anonArgs = 0
> }
> (>>>) :: Arrow -> Arrow -> Arrow
> a1 >>> a2 = a1 { code = compose (code a1) (code a2) }
> arrowExp :: HsExp -> Arrow
> arrowExp e = Arrow {
> code = if e == returnA_exp then ReturnA else Op e [],
> context = emptyTuple,
> anonArgs = 0
> }
> applyOp :: HsExp -> [Arrow] -> Arrow
> applyOp e as = Arrow {
> code = Op e (map code as),
> context = foldr unionTuple emptyTuple (map context as),
> anonArgs = 0
> }
Setting anonArgs to 0 for infixOp is incorrect, but we can't know the
correct value without types.
> infixOp :: Arrow -> HsQOp -> Arrow -> Arrow
> infixOp a1 op a2 = Arrow {
> code = InfixOp (code a1) op (code a2),
> context = context a1 `unionTuple` context a2,
> anonArgs = 0
> }
> first :: Arrow -> Tuple -> Arrow
> first a ps = Arrow {
> code = Op first_exp [code a],
> context = context a `unionTuple` ps,
> anonArgs = 0
> }
> (|||) :: Arrow -> Arrow -> Arrow
> a1 ||| a2 = Arrow {
> code = InfixOp (code a1) choice_op (code a2),
> context = context a1 `unionTuple` context a2,
> anonArgs = 0
> }
> letCmd :: [VarDecl Arrow] -> Arrow -> Arrow
> letCmd defs a = Arrow {
> code = Let (map (fmap code) defs) (code a),
> context = context a,
> anonArgs = anonArgs a
> }
Composition, with some simplification
> compose :: Code -> Code -> Code
> compose ReturnA a = a
> compose a ReturnA = a
> compose a1@(Arr n1 p1 ds1 e1) a2@(Arr n2 p2 ds2 e2)
> | n1 /= n2 = Compose a1 [] a2
> | same p2 e1 = Arr n1 p1 (ds1 ++ ds2) e2
> | otherwise = Arr n1 p1 (ds1 ++ BindCase p2 e1:ds2) e2
> where same :: HsPat -> HsExp -> Bool
> same (HsPApp n1 []) (HsCon n2) = n1 == n2
> same (HsPVar n1) (HsVar n2) = UnQual n1 == n2
> same (HsPTuple ps) (HsTuple es) =
> length ps == length es && and (zipWith same ps es)
> same (HsPParen p) e = same p e
> same p (HsParen e) = same p e
> same _ _ = False
> compose (Compose f1 as1 g1) (Compose f2 as2 g2) =
> Compose f1 (as1 ++ (compose g1 f2 : as2)) g2
> compose a (Compose f bs g) =
> Compose (compose a f) bs g
> compose (Compose f as g) b =
> Compose f as (compose g b)
> compose a1 a2 =
> Compose a1 [] a2
-----------------------------------------------------------------------------
Conversion to Haskell
> toHaskell :: Arrow -> HsExp
> toHaskell = toHaskellCode . code
> toHaskellCode :: Code -> HsExp
> toHaskellCode ReturnA =
> returnA_exp
> toHaskellCode (Arr n p bs e) =
> HsApp arr_exp
> (times n (HsParen . HsApp first_exp) body)
> where body = HsParen (HsLambda undefined [p] (foldr addBinding e bs))
> addBinding :: Binding -> HsExp -> HsExp
> addBinding (BindLet ds) e = HsLet ds e
> addBinding (BindCase p e) e' =
> HsCase e [HsAlt undefined p (HsUnGuardedAlt e') []]
> toHaskellCode (Compose f as g) =
> foldr comp (toHaskellArg g) (map toHaskellArg (f:as))
> where comp f g = HsInfixApp f compose_op g
> toHaskellCode (Op op as) =
> foldl HsApp op (map (paren . toHaskellCode) as)
> toHaskellCode (InfixOp a1 op a2) =
> HsInfixApp (toHaskellArg a1) op (toHaskellArg a2)
> toHaskellCode (Let nas a) =
> HsLet (map toHaskellDecl nas) (toHaskellCode a)
> where toHaskellDecl (VarDecl loc n a) =
> HsPatBind loc (HsPVar n)
> (HsUnGuardedRhs (toHaskellCode a)) []
> toHaskellCode (Ifte cond th el) = HsIf cond (toHaskellCode th) (toHaskellCode el)
> toHaskellArg :: Code -> HsExp
> toHaskellArg a = parenInfixArg (toHaskellCode a)
-----------------------------------------------------------------------------
Tuples, representing sets of variables.
> newtype Tuple = Tuple (Set HsName)
Tuple extractors, including matching expression and pattern.
> isEmptyTuple :: Tuple -> Bool
> isEmptyTuple (Tuple t) = Set.null t
> patternTuple :: Tuple -> HsPat
> patternTuple (Tuple t) = tupleP (map HsPVar (Set.toList t))
> expTuple :: Tuple -> HsExp
> expTuple (Tuple t) = tuple (map (HsVar . UnQual) (Set.toList t))
Operations on tuples
> emptyTuple :: Tuple
> emptyTuple = Tuple Set.empty
> unionTuple :: Tuple -> Tuple -> Tuple
> unionTuple (Tuple a) (Tuple b) = Tuple (a `Set.union` b)
Remove all usages of a set of variables.
> minusTuple :: Tuple -> Set HsName -> Tuple
> Tuple t `minusTuple` vs = Tuple (t `Set.difference` vs)
> intersectTuple :: Tuple -> Set HsName -> Tuple
> Tuple t `intersectTuple` vs = Tuple (t `Set.intersection` vs)