module FunctorOf ( getCtx , functorOfInst , getSeed , hsPat2Exp ) where import Data.Map hiding (map) import Data.List import Data.Maybe import Language.Haskell.Exts.Syntax as Exts import Control.Monad.State import Data.Char (isUpper) import Data.Generics hiding (Unit,(:*:),Inl,Inr) import Language.Haskell.Exts.Parser import Language.Haskell.Exts.Pretty import Language.Pointwise.Parser (hsPat2Exp) import Language.Pointwise.Syntax as Pointwise hiding (swap) -- Associates a constructor to definition type Ctx = [(String,Term)] getCtx :: Module -> Ctx getCtx (Module _ _ _ _ _ decls) = concat $ catMaybes $ map getCtxDecl decls getCtxDecl :: Decl -> Maybe Ctx getCtxDecl (DataDecl _ _ _ _ _ cons _) = getCtxCons cons In getCtxDecl _ = fail "Only applies to data declarations" getCtxCons :: [QualConDecl] -> (Term -> Term) -> Maybe Ctx getCtxCons [QualConDecl _ _ _ (ConDecl (Ident name) l)] f = return [(name, buildArgs f (length l))] getCtxCons ((QualConDecl _ _ _ (ConDecl (Ident name) l)):t) f = do t' <- getCtxCons t (f . Inr) return ((name, buildArgs (f . Inl) (length l)):t') getCtxCons _ _ = fail "Case not covered" buildArgs :: (Term -> Term) -> Int -> Term buildArgs f 0 = f Unit buildArgs f 1 = Lam "x1" (f (Pointwise.Var "x1")) buildArgs f n = let v = "x"++(show n) in Lam v (buildArgs (f . (\t -> (Pointwise.Var v :&: t))) (n-1)) {- Calculation of the instances of FunctorOf, when possible. -} type St = StateT (String,Int) Maybe conDecl :: QualConDecl -> ConDecl conDecl (QualConDecl _ _ _ con) = con functorOfInst :: Bool -> Module -> Module functorOfInst ob (Module a b c d i decls) = let seed = "v" --getSeed decls newDecls = concat $ catMaybes $ map (\x -> evalStateT (getInstances ob x) (seed,0)) decls in Module a b c d i (decls ++ newDecls) g :: Type -> QualConDecl -> St Type g arg = gCon arg . conDecl gCon :: Type -> ConDecl -> St Type gCon arg (ConDecl _ []) = return constNil gCon arg (ConDecl _ lBangType) = mapM (h arg) lBangType >>= return . foldr1 timesType gCon arg (RecDecl hsName l ) = gCon arg (ConDecl hsName (concatMap unRec l)) -- fail "data types records not yet supported" h :: Type -> BangType -> St Type h arg (BangedTy hsType ) = ii arg hsType h arg (UnBangedTy hsType ) = ii arg hsType -- what's the diference between Banged and UnBanged? i :: Type -> Type -> St Type i arg (TyFun hsType1 hsType2) = fail "TyFun not yet supported" i arg (TyTuple _ lType) = mapM (ii arg) lType >>= return . foldr1 timesType i arg (TyApp hsType1 hsType2) = i arg hsType2 >>= return . appType hsType1 -- fail "TyApp not yet supported" --g :@: h i arg t@(TyVar hsName) = return $ TyApp (TyCon $ UnQual $ Ident "Const") t i arg t@(TyCon hsQName) = return $ TyApp (TyCon $ UnQual $ Ident "Const") t ii :: Type -> Type -> St Type ii arg typ | typ == arg = return $ TyCon $ UnQual $ Ident "Id" | otherwise = i arg typ genInOut :: Type -> [QualConDecl] -> St [(Pat, Pat)] genInOut arg [] = fail "empty list of constructors" genInOut arg l = mapM (g' arg) l >>= return . genPat genPat :: [(Pat, Pat)] -> [(Pat, Pat)] genPat [] = error "empty list found when generating instance of 'Mu' " genPat l = genPatAux id l genPatAux ac [(a,b)] = [(ac a, b)] genPatAux ac ((a,b):t) = (ac . inl $ a, b) : genPatAux (ac . inr) t g' :: Type -> QualConDecl -> St (Pat,Pat) g' arg = g'Con arg . conDecl g'Con :: Type -> ConDecl -> St (Pat, Pat) g'Con arg (ConDecl hsName []) = return (constPNil,PApp (UnQual hsName) []) g'Con arg (ConDecl hsName lBangType) = do (l2,l3) <- mapAndUnzipM (h' arg) lBangType return (foldr1 times l2,PApp (UnQual hsName) l3) g'Con arg (RecDecl hsName l) = g'Con arg (ConDecl hsName (concatMap unRec l)) --fail "data types records not yet supported" h' :: Type -> BangType -> St (Pat, Pat) h' arg (BangedTy hsType) = ii' arg hsType h' arg (UnBangedTy hsType) = ii' arg hsType -- what's the diference between Banged and UnBanged? i' :: Type -> Type -> St (Pat, Pat) i' arg (TyFun hsType1 hsType2) = fail "TyFun not yet supported" i' arg (TyTuple _ lType) = do (l1,l2) <- mapAndUnzipM (ii' arg) lType return (foldr1 times l1,PTuple l2) i' arg (TyApp hsType1 hsType2) = do a <- getFreshVar let av = PVar a return (av,av) i' arg t@(TyVar hsName) = do a <- getFreshVar let av = PVar a return (av,av) i' arg t@(TyCon hsQName) = do a <- getFreshVar let av = case hsQName of Special _ -> PApp hsQName [] _ -> PVar a return (av,av) ii' :: Type -> Type -> St (Pat, Pat) ii' arg typ | typ == arg = do a <- getFreshVar let av = PVar a return (av,av) | otherwise = i' arg typ mkDataName :: Decl -> Type mkDataName (DataDecl _ _ _ hsName lName _ _) = foldl TyApp (TyCon $ UnQual hsName) . map TyVar $ lName getDataDeclFunctor :: Type -> [QualConDecl] -> St Type getDataDeclFunctor arg lConDecl = do l1 <- mapM (g arg) lConDecl let functor = foldr1 plusType l1 return functor getInstances :: Bool -- ^ Observable or not -> Decl -- ^ Data types -> St [Decl] -- ^ Instances for functor representation getInstances ob d@(DataDecl loc _ [] hsName lName lConDecl _) = do let arg = mkDataName d functor <- getDataDeclFunctor arg lConDecl l <- genInOut arg lConDecl let innOut = [InsDecl (FunBind (map inMatch l)), InsDecl (FunBind (map outMatch l))] let pfTInst = TypeInsDecl loc (TyApp pfType arg) functor let muInst = InstDecl loc [] mu [arg] innOut let observableInst = getObservableInst loc arg if ob then return [pfTInst,muInst,observableInst] else return [pfTInst,muInst] where match str (a,b) = Exts.Match mkLoc (Ident str) [a] (UnGuardedRhs $ hsPat2Exp b) (BDecls []) mkLoc = SrcLoc "" 0 0 inMatch = match "inn" outMatch = match "out" . swap getInstances _ (DataDecl _ _ _ _ _ _ _ ) = fail "type context not treated" getInstances _ _ = fail "not a data declaration" -- types opType op a b = TyApp (TyApp (TyVar $ Symbol op) a ) b plusType = opType ":+:" timesType = opType ":*:" appType = opType ":@:" constNil = TyApp (TyCon $ UnQual $ Ident "Const") (TyCon $ UnQual $ Ident "One") mu = UnQual $ Ident "Mu" pfType = TyCon $ UnQual $ Ident "PF" -- patterns constPNil = PWildCard inl = PApp (UnQual $ Ident "Left") . singl . PParen inr = PApp (UnQual $ Ident "Right") . singl . PParen singl = (:[]) times a b = PTuple [a,b] unRec (a,b) = replicate (length a) b getFreshVar = do (seed,n) <- gets id modify (\_->(seed,n+1)) return $ Ident $ seed ++ show (n+1) getObservableInst :: SrcLoc -> Type -> Decl getObservableInst loc a = InstDecl loc [ClassA (UnQual (Ident "FunctorO")) [TyApp (TyCon (UnQual (Ident "PF"))) a]] (UnQual (Ident "Observable")) [a] [InsDecl (FunBind [Exts.Match loc (Ident "observer") [PVar (Ident "x")] (UnGuardedRhs (App (App (Exts.Var (UnQual (Ident "send"))) (Lit (String ""))) (Paren (InfixApp (InfixApp (App (App (App (Exts.Var (UnQual (Ident "omap"))) (Paren (ExpTypeSig loc (Exts.Var (UnQual (Ident "_L"))) a))) (Exts.Var (UnQual (Ident "thk")))) (Paren (App (Exts.Var (UnQual (Ident "out"))) (Exts.Var (UnQual (Ident "x")))))) (QVarOp (UnQual (Symbol ">>="))) (Exts.Var (UnQual (Ident "return")))) (QVarOp (UnQual (Symbol "."))) (Exts.Var (UnQual (Ident "inn"))))))) (BDecls [PatBind loc (PVar (Ident "thk")) (UnGuardedRhs (ExpTypeSig loc (Exts.Var (UnQual (Ident "thunk"))) (TyFun a (TyApp (TyCon (UnQual (Ident "ObserverM"))) a)))) (BDecls [])])])] ---- auxiliary functions swap (a,b) = (b,a) showName (Ident s) = s showQName (UnQual (Ident s)) = s showQName (Qual (ModuleName s1) (Ident s2)) = s1++('.':s2) getSeed :: Data a => a -> String getSeed = flip replicate 'x' . maximum . (1:) . everything (++) (mkQ [] aux) where aux = (:[]) . (+1) . length . takeWhile (=='x')