packages feed

DrHylo-0.0.1: src/FunctorOf.hs

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')