thorn 0.1.0.3 → 0.2
raw patch · 9 files changed
+889/−566 lines, 9 files
Files
- Data/Thorn.hs +8/−117
- Data/Thorn/Basic.hs +20/−0
- Data/Thorn/Fold.hs +339/−105
- Data/Thorn/FoldExample.hs +0/−16
- Data/Thorn/Functor.hs +217/−24
- Data/Thorn/FunctorExample.hs +0/−59
- Data/Thorn/Internal.hs +292/−0
- Data/Thorn/Type.hs +0/−241
- thorn.cabal +13/−4
Data/Thorn.hs view
@@ -1,125 +1,16 @@--- | Thorn, Datatype Manipulation with Template Haskell. +-- | +-- Thorn, Datatype Manipulation with Template Haskell. module Data.Thorn ( - -- * Functor - -- $functor - autofmap - , Variance(..) - , autovariance, autofunctorize - + -- * Functors + module Data.Thorn.Functor -- * Folding and Unfolding - -- $fold - , unfixdata, unfixdataEx - , autoin, autoout, autohylo, autofold, autounfold - - -- * Type Variants - -- $typevariants - , T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 - - -- * Example - - -- ** Functor Example - -- $functorexample - - -- ** Folding and Unfolding Example - -- $foldexample + , module Data.Thorn.Fold + -- * Basic + , module Data.Thorn.Basic ) where -import Data.Thorn.Type import Data.Thorn.Functor import Data.Thorn.Fold - -{- $functor - Thorn generates functors from various kinds of data types. - - Quite surprisingly, it still works for any arities, co\/contra\/free\/fixed-variances, partially applied types, type synonyms, and mutual recursions. - - For more information, see <Data-Thorn.html#FunctorExample Functor Example>. --} - -{- $fold - For more information, see <Data-Thorn.html#FoldExample Folding and Unfolding Example>. --} - -{- $typevariants - These types are used for representing type variants. For more information, see <Data-Thorn.html#FunctorExample Functor Example>. --} - -{- $functorexample - #FunctorExample# - -> import Data.Thorn -> import Data.Char -> import Data.Functor.Contravariant -> import Data.Bifunctor -> import Data.Profunctor -> -> type a :<- b = b -> a -> nuf :: Char -> nuf = $(autofmap [t|(:<-)|]) chr ord (+1) 'a' -- 'b' -> varnuf :: [Variance] -> varnuf = $(autovariance [t|(:<-)|]) -- [Co,Contra] -> -> data Cntr a = Cntr (a -> Int) -> autofunctorize [t|Cntr|] -- instance Contravariant Cntr where ... -> -> tuple :: (Int,Int,Int) -> tuple = $(autofmap $[t|(,,) Int|]) (+1) (+2) (0,0,0) -- (0,1,2) -> vartuple :: [Variance] -> vartuple = $(autovariance [t|(,,) Int|]) -- [Co,Co] -> -> data FunFun a b = FunFun ((b -> a) -> b) -> varfunfun :: [Variance] -> varfunfun = $(autovariance [t|FunFun|]) -- [Contra,Co] -> autofunctorize [t|FunFun|] -- instance Profunctor FunFun where ... -> -> data What a b c = What1 c (a -> c) | What2 a -> varwhat :: [Variance] -> varwhat = $(autovariance [t|What|]) -- [Fixed,Free,Co] -> autofunctorize [t|What T0|] -> -- instance Bifunctor (What a) where ... and -> -- instance Profunctor (What a) where ... -> -> data List a = Nil | a :* (List a) deriving Show -> fromNormalList :: [a] -> List a -> fromNormalList [] = Nil -> fromNormalList (a : as) = a :* fromNormalList as -> toNormalList :: List a -> [a] -> toNormalList Nil = [] -> toNormalList (a :* as) = a : toNormalList as -> list :: [Int] -> list = toNormalList $ $(autofmap [t|List|]) (+10) (fromNormalList [1..5]) -- [11..15] -> varlist :: [Variance] -> varlist = $(autovariance [t|List|]) -- [Co] -> autofunctorize [t|List|] -- instance Functor List where ... -> -> data Rose a = Rose a (Forest a) deriving Show -> data Forest a = Forest [Rose a] deriving Show -> gorose n = Rose n (Forest (replicate n (gorose (n-1)))) -> rose = $(autofmap [t|Rose|]) (+1) (gorose 2) -> varrose, varforest :: [Variance] -> varrose = $(autovariance [t|Rose|]) -- [Co] -> varforest = $(autovariance [t|Forest|]) -- [Co] -> autofunctorize [t|Rose|] -- instance Functor Rose where ... -> autofunctorize [t|Forest|] -- instance Functor Forest where ... - - - --} - -{- $foldexample - #FoldExample# - -> import Data.Thorn -> -> data x :$ y = Nil | (x,y) :* (x :$ y) -> -> unfixdata [t|(:$)|] -> -> insth = $(autoin [t|(:&$)|] [t|(:$)|]) -> outsth = $(autoout [t|(:&$)|] [t|(:$)|]) -> hylosth = $(autohylo [t|(:&$)|]) -> foldsth = $(autofold [t|(:&$)|] [t|(:$)|]) -> unfoldsth = $(autounfold [t|(:&$)|] [t|(:$)|]) --} +import Data.Thorn.Basic
+ Data/Thorn/Basic.hs view
@@ -0,0 +1,20 @@+-- | +-- The module Data.Thorn.Basic. +module Data.Thorn.Basic ( + -- * Type Variants + -- $typevariants + T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 + + -- * Names + , modifyname + ) where + +import Data.Thorn.Internal + +{- $typevariants + These types @'T0', ..., 'T9'@ are used for representing type variants. + +> testtypevariant :: (String,Int,Int) +> testtypevariant = $(autofmap $[t|(,,) T0|]) (+10) (+20) ("hello",1,1) -- ("hello",11,21) +-} +
Data/Thorn/Fold.hs view
@@ -3,148 +3,382 @@ -- | -- The module Data.Thorn.Fold. module Data.Thorn.Fold ( - unfixdata, unfixdataEx - , autoin, autoout, autohylo, autofold, autounfold - , unfixdataMutual, unfixdataMutualEx - , autoinMutual, autooutMutual, autohyloMutual, autofoldMutual, autounfoldMutual + -- * Folding and Unfolding + -- $fold + unfixdata, autofold, autofoldtype, autofolddec, autounfold, autounfoldtype, autounfolddec + -- ** Mutual Recursion + , unfixdataMutual, autofoldMutual, autofoldtypeMutual, autofolddecMutual, autounfoldMutual, autounfoldtypeMutual, autounfolddecMutual + -- ** Helper Function + , modifynameUf + -- ** Primitive Functions + , autoin, autoout, autohylo + , autoinMutual, autooutMutual, autohyloMutual + + -- * Examples + -- ** Basic + -- $basic + + -- ** Mutual Recursion + -- $mutual ) where -import Data.Thorn.Type +import Data.Thorn.Internal import Data.Thorn.Functor import Language.Haskell.TH +import Data.List import Control.Applicative +{- $fold + Thorn generates folds and unfolds from various kinds of recursive datatypes, including mutually recursive ones. +-} + +{- $basic + +It's a piece of cake. + +Note tht @foldlist@ is analogous with 'foldr' and @unfoldlist@ with 'unfoldr'. + +> data List a = Nil | a :* (List a) deriving Show +> +> unfixdata [t|List|] "UfList" modifynameUf [''Show] +> -- data UfList a self = UfNil | a :&* self deriving Show +> +> autofolddec "foldlist" [t|UfList|] [t|List|] +> autounfolddec "unfoldlist" [t|UfList|] [t|List|] +> +> fib :: List Int +> fib = unfoldlist go (0,1) +> -- 1 :* (1 :* (2 :* (3 :* (5 :* (8 :* (13 :* Nil)))))) +> where go :: (Int,Int) -> UfList Int (Int,Int) +> go (a,b) +> | b > 20 = UfNil +> | otherwise = b :&* (b,a+b) +> +> fibsum :: Int +> fibsum = foldlist add fib +> -- 33 +> where add :: UfList Int Int -> Int +> add UfNil = 0 +> add (m :&* n) = m+n +> +> normalfib :: [Int] +> normalfib = foldlist go fib +> -- [1,1,2,3,5,8,13] +> where go :: UfList a [a] -> [a] +> go UfNil = [] +> go (a :&* as) = a:as + +-} + +{- $mutual + +It also works for mutual recursion. + +It's just an extension of simple recursion. Take it easy. + +> data Rose x = x :-< (Forest x) deriving Show +> data Forest x = F [Rose x] deriving Show +> +> unfixdataMutual [([t|Rose|],"UfRose",modifynameUf,[''Show]), ([t|Forest|],"UfForest",modifynameUf,[''Show])] +> -- data UfRose x rose forest = x :&-< forest deriving Show +> -- data UfForest x rose forest = UfF [rose] deriving Show +> +> autofolddecMutual "foldrose" [([t|UfRose|],[t|Rose|]),([t|UfForest|],[t|Forest|])] 0 +> -- foldrose :: (UfRose x a b -> a) -> (UfForest x a b -> b) -> Rose x -> a +> -- foldrose = ... +> autounfolddecMutual "unfoldrose" [([t|UfRose|],[t|Rose|]),([t|UfForest|],[t|Forest|])] 0 +> -- unfoldrose :: (a -> UfRose x a b) -> (b -> UfForest x a b) -> a -> Rose x +> -- unfoldrose = ... +> +> rose :: Rose Int +> rose = unfoldrose gorose goforest 0 +> -- 0 :-< F [1 :-< F [3 :-< F [],4 :-< F []],2 :-< F [5 :-< F [],6 :-< F []]] +> where gorose :: Int -> UfRose Int Int Int +> gorose n +> | n > 2 = n :&-< (-1) +> | otherwise = n :&-< n +> goforest :: Int -> UfForest Int Int Int +> goforest (-1) = UfF [] +> goforest n = UfF [n*2+1,n*2+2] +> +> showrose :: Show x => Rose x -> String +> showrose = unlines . foldrose gorose goforest +> where gorose :: Show x => UfRose x [String] [String] -> [String] +> gorose (x :&-< ls) = [show x] ++ ls +> goforest :: UfForest x [String] [String] -> [String] +> goforest (UfF []) = [] +> goforest (UfF lss) = concatMap hang (init lss) ++ hang' (last lss) +> hang ls = ["|"] ++ ["+--" ++ head ls] ++ map ("| "++) (tail ls) +> hang' ls = ["|"] ++ ["+--" ++ head ls] ++ map (" "++) (tail ls) +> +> shownrose :: String +> shownrose = showrose rose +> -- 0 +> -- | +> -- +--1 +> -- | | +> -- | +--3 +> -- | | +> -- | +--4 +> -- | +> -- +--2 +> -- | +> -- +--5 +> -- | +> -- +--6 + +-} + -- | --- @unfixdata t@ provides a declaration of a data whose fixpoint is the recursive type @t@. -unfixdata :: TypeQ -> DecsQ -unfixdata = unfixdataEx ("Uf","") ("Uf","") ("&","") ("&","") +-- Use this function to designate how to convert the name of data constructors for 'unfixdata'. +-- +-- > modifynameUf "Hello" == "UfHello" +-- > modifynameUf ":***" == ":&***" +-- +-- Note that +-- +-- @'modifynameUf' == 'modifyname' (\"Uf\",\"\") (\"&\",\"\")@ +modifynameUf :: String -> String +modifynameUf = modifyname ("Uf","") ("&","") -- | --- Special version of @unfixdata@. Note that --- --- > unfixdata = unfixdataEx ("Uf","") ("Uf","") ("&","") ("&","") -unfixdataEx :: - (String,String) -- ^ prefix and suffix of type constructor - -> (String,String) -- ^ prefix and suffix of data constructor - -> (String,String) -- ^ prefix and suffix of infix type constructor - -> (String,String) -- ^ prefix and suffix of infix data constructor - -> TypeQ -- ^ data type - -> DecsQ -- ^ declaration of data -unfixdataEx (pretype,suftype) (predata,sufdata) (pretypeinfix,suftypeinfix) (predatainfix,sufdatainfix) t = do - (n, DataTx nm _ cxs) <- applyFixed 0 =<< type2typex [] [] =<< t - let modifytx (DataTx nm' vmp cxs') = if nm == nm' then VarTx $ mkName ("self") else DataTx nm' (map (\(nm'',tx) -> (nm'',modifytx tx)) vmp) (map modifycx cxs') - modifytx tx@(SeenDataTx nm' _) = if nm == nm' then VarTx $ mkName ("self") else modifytx tx - modifytx (TupleTx txs) = TupleTx (map modifytx txs) - modifytx (ArrowTx txa txb) = ArrowTx (modifytx txa) (modifytx txb) - modifytx (ListTx tx) = ListTx (modifytx tx) - modifytx tx = tx - modifycx (nm',txs) = (nm',map modifytx txs) - go (nm',txs) = do - ts <- map ((,) NotStrict) <$> mapM (typex2type . modifytx) txs - return $ NormalC (datanm nm') ts - cns <- mapM go cxs - return [DataD [] (typenm nm) (map var [0..n-1] ++ [self]) cns []] - where typenm nm - | elem (head s) ['A'..'Z'] = mkName $ pretype ++ s ++ suftype - | head s == '(' = mkName $ ":" ++ pretypeinfix ++ init (drop 2 s) ++ suftypeinfix - | otherwise = mkName $ ":" ++ pretypeinfix ++ tail s ++ suftypeinfix - where s = nameBase nm - datanm nm - | elem (head s) ['A'..'Z'] = mkName $ predata ++ s ++ sufdata - | head s == '(' = mkName $ ":" ++ predatainfix ++ init (drop 2 s) ++ sufdatainfix - | otherwise = mkName $ ":" ++ predatainfix ++ tail s ++ sufdatainfix - where s = nameBase nm - var i = PlainTV $ mkName ("t" ++ show i) - self = PlainTV $ mkName ("self") +-- @unfixdata t n f ds@ provides a declaration of a nonrecursive datatype whose fixpoint is the recursive type @t@, with a deriving declaration with names @ds@. +unfixdata :: + TypeQ -- ^ @t@, recursive datatype + -> String -- ^ @s@, name of the datatype to be declared + -> (String -> String) -- ^ @f@, how to convert the name of data constructors + -> [Name] -- ^ @ds@, derivings + -> DecsQ -- ^ declaration of a nonrecursive datatype whose fixpoint is @t@ +unfixdata t s f ds = unfixdataMutual [(t,s,f,ds)] autoin :: - TypeQ -- ^ @u@, un-recursive datatype + TypeQ -- ^ @u@, nonrecursive datatype -> TypeQ -- ^ @t@, fixpoint of @u@ - -> ExpQ -- ^ function with a type @u a0 .. an t -> t a0 .. an@ -autoin u t = do - (_,DataTx _ _ cxsu) <- applyFixed 0 =<< type2typex [] [] =<< u - (_,DataTx _ _ cxst) <- applyFixed 0 =<< type2typex [] [] =<< t - u1 <- unique - u2 <- unique - let go ((nmu,txsu),(nmt,_)) = Match (ConP nmu (map newVarP [u2..u2+length txsu-1])) (NormalB (applistE (ConE nmt) (map newVarE [u2..u2+length txsu-1]))) [] - return $ LamE [newVarP u1] (CaseE (newVarE u1) (map go (zip cxsu cxst))) + -> ExpQ -- ^ function with a type @u x0 .. xn t -> t x0 .. xn@ +autoin u t = autoinMutual [(u,t)] 0 autoout :: - TypeQ -- ^ @u@, un-recursive datatype + TypeQ -- ^ @u@, nonrecursive datatype -> TypeQ -- ^ @t@, fixpoint of @u@ -> ExpQ -- ^ function with a type @t x0 .. xn -> u x0 .. xn t@ -autoout u t = do - (_,DataTx _ _ cxsu) <- applyFixed 0 =<< type2typex [] [] =<< u - (_,DataTx _ _ cxst) <- applyFixed 0 =<< type2typex [] [] =<< t - u1 <- unique - u2 <- unique - let go ((nmu,txsu),(nmt,_)) = Match (ConP nmt (map newVarP [u2..u2+length txsu-1])) (NormalB (applistE (ConE nmu) (map newVarE [u2..u2+length txsu-1]))) [] - return $ LamE [newVarP u1] (CaseE (newVarE u1) (map go (zip cxsu cxst))) +autoout u t = autooutMutual [(u,t)] 0 autohylo :: - TypeQ -- ^ @u@, un-recursive datatype + TypeQ -- ^ @u@, nonrecursive datatype -> ExpQ -- ^ function with a type @(a -> u x0 .. xn a) -> (u x0 .. xn b -> b) -> (a -> b)@ -autohylo u = do - (n,DataTx nm _ cxs) <- applyFixed 0 =<< type2typex [] [] =<< u - f <- autofmap u - u <- unique - return $ LamE [newVarP u, newVarP (u+1)] (LetE [ValD (newVarP (u+3)) - (NormalB (LamE [newVarP (u+2)] (AppE (newVarE (u+1)) (applistE f (replicate (n-1) (mkNameE "Prelude.id") ++ [newVarE (u+3)] ++ [AppE (newVarE u) (newVarE (u+2))]))))) - []] (newVarE (u+3))) +autohylo u = autohyloMutual [u] 0 -- | --- @autofold u t@ provides a folding function for a recursive type @t@. +-- @autofold u t@ provides a fold for the recursive type @t@. autofold :: - TypeQ -- ^ @u@, un-recursive datatype + TypeQ -- ^ @u@, nonrecursive datatype -> TypeQ -- ^ @t@, fixpoint of @u@ - -> ExpQ -- ^ function with a type @(u x0 .. xn a -> a) -> (t -> a)@ -autofold u t = do - o <- autoout u t - h <- autohylo u - return $ AppE h o + -> ExpQ -- ^ fold with a type @(u x0 .. xn a -> a) -> (t x0 .. xn -> a)@ +autofold u t = autofoldMutual [(u,t)] 0 -- | --- @autounfold t@ provides an unfolding function for the recursive type @t@. +-- @autofoldtype u t@ provides the type of @$('autofold' u t)@, that is, @(u x0 .. xn a -> a) -> (t x0 .. xn -> a)@. +autofoldtype :: TypeQ -> TypeQ -> TypeQ +autofoldtype u t = autofoldtypeMutual [(u,t)] 0 + +-- | +-- @autofolddec s u t@ provides a declaration of a fold for the recursive type @t@ with the name @s@, with a type signature. +autofolddec :: String -> TypeQ -> TypeQ -> DecsQ +autofolddec = gendec2 autofold autofoldtype + +-- | +-- @autounfold u t@ provides an unfold for the recursive type @t@. autounfold :: - TypeQ -- ^ @u@, un-recursive datatype + TypeQ -- ^ @u@, nonrecursive datatype -> TypeQ -- ^ @t@, fixpoint of @u@ - -> ExpQ -- ^ function with a type @(a -> u x0 .. xn a) -> (a -> t)@ + -> ExpQ -- ^ unfold with a type @(a -> u x0 .. xn a) -> (a -> t x0 .. xn)@ autounfold u t = do - i <- autoin u t - h <- autohylo u + e <- autounfoldMutual [(u,t)] 0 + return e + +-- | +-- @autounfoldtype u t@ provides the type of @$('autounfold' u t)@, that is, @(a -> u x0 .. xn a) -> (a -> t x0 .. xn)@. +autounfoldtype :: TypeQ -> TypeQ -> TypeQ +autounfoldtype u t = autounfoldtypeMutual [(u,t)] 0 + +-- | +-- @autounfolddec s u t@ provides a declaration of an unfold for the recursive type @t@ with the name @s@, with a type signature. +autounfolddec :: String -> TypeQ -> TypeQ -> DecsQ +autounfolddec = gendec2 autounfold autounfoldtype + +-- | +-- Mutually recursive version of 'unfixdata'. Note that +-- +-- @'unfixdata' t s f ds = 'unfixdataMutual' [(t,s,f,ds)]@ +unfixdataMutual :: + [(TypeQ,String,String->String,[Name])] -- ^ @[(t0,s0,f0,ds0), ...]@; recursive datatype, name of the datatype to be declared, how to convert the name of data constructors, and derivings + -> DecsQ -- ^ declarations of datatypes @u0, u1, u2, ...@, whose fixpoints are @t0, t1, t2, ...@ respectively +unfixdataMutual tsfdss = do + tpls <- mapM (\(t,_,_,_) -> t >>= type2typex [] [] >>= applyFixed 0) tsfdss + let nms = map (\(_, DataTx nm _ _) -> nm) tpls + cxss = map (\(_, DataTx _ _ cxs) -> cxs) tpls + ss = map (\(_,s,_,_) -> s) tsfdss + fs = map (\(_,_,f,_) -> f) tsfdss + dss = map (\(_,_,_,ds) -> ds) tsfdss + l = length tpls + (n,_) = head tpls + modifytx (DataTx nm vmp cxs) = case elemIndex nm nms of + Just k -> VarTx $ mkName ("self" ++ show k) + Nothing -> DataTx nm (map (\(nm',tx) -> (nm',modifytx tx)) vmp) (map modifycx cxs) + modifytx tx@(SeenDataTx nm _) = case elemIndex nm nms of + Just k -> VarTx $ mkName ("self" ++ show k) + Nothing -> tx + modifytx (TupleTx txs) = TupleTx (map modifytx txs) + modifytx (ArrowTx txa txb) = ArrowTx (modifytx txa) (modifytx txb) + modifytx (ListTx tx) = ListTx (modifytx tx) + modifytx tx = tx + modifycx (nm,txs) = (nm,map modifytx txs) + go f (nm,txs) = do + ts' <- map ((,) NotStrict) <$> mapM (typex2type . modifytx) txs + return $ NormalC (fixname f nm) ts' + ho (nm,s,cns,ds) = DataD [] newnm (map var [0..n-1] ++ map self [0..l-1]) cns ds + where newnm = if s=="" then fixname (modifyname ("Uf","") ("&","")) nm else mkName s + cnss <- mapM (\(cxs,f) -> mapM (go f) cxs) (zip cxss fs) + return $ map ho (zip4 nms ss cnss dss) + where var i = PlainTV $ mkName ("t" ++ show i) + self i = PlainTV $ mkName ("self" ++ show i) + +-- | +-- Mutually recursive version of 'autoin'. +autoinMutual :: + [(TypeQ,TypeQ)] -- ^ @[(u0,t0), .., (un,tn)]@; @ui@ is a nonrecursive datatype and @ti@ is a fixpoint of @ui@ + -> Int -- ^ @k@, index + -> ExpQ -- ^ function with a type @uk x0 .. xm t0 .. tn -> tk x0 .. xm@ +autoinMutual uts k = do + cxsus <- mapM (\(u,_) -> u >>= type2typex [] [] >>= applyFixed 0 >>= return . getcxs . snd) uts + cxsts <- mapM (\(_,t) -> t >>= type2typex [] [] >>= applyFixed 0 >>= return . getcxs . snd) uts + let cxsu = cxsus !! k + cxst = cxsts !! k u1 <- unique - return $ LamE [newVarP u1] (AppE (AppE h (newVarE u1)) i) + u2 <- unique + let go ((nmu,txsu),(nmt,_)) = Match (ConP nmu (map newVarP [u2..u2+l-1])) (NormalB (applistE (ConE nmt) (map newVarE [u2..u2+l-1]))) [] + where l = length txsu + return $ LamE [newVarP u1] (CaseE (newVarE u1) (map go (zip cxsu cxst))) + where getcxs (DataTx _ _ cxs) = cxs + getcxs _ = error "Thorn doesn't work well, sorry." -- | --- @unfixdataMutual ts@ is a mutual recursion version of @unfixdata t@. -unfixdataMutual :: [TypeQ] -> DecsQ -unfixdataMutual = unfixdataMutualEx ("Uf","") ("Uf","") ("&","") ("&","") +-- Mutually recursive version of 'autoout'. +autooutMutual :: + [(TypeQ,TypeQ)] -- ^ @[(u0,t0), .., (un,tn)]@; @ui@ is a nonrecursive datatype and @ti@ is a fixpoint of @ui@ + -> Int -- ^ @k@, index + -> ExpQ -- ^ function with a type @tk x0 .. xm -> uk x0 .. xm t0 .. tn@ +autooutMutual uts k = do + cxsus <- mapM (\(u,_) -> u >>= type2typex [] [] >>= applyFixed 0 >>= return . getcxs . snd) uts + cxsts <- mapM (\(_,t) -> t >>= type2typex [] [] >>= applyFixed 0 >>= return . getcxs . snd) uts + let cxsu = cxsus !! k + cxst = cxsts !! k + u1 <- unique + u2 <- unique + let go ((nmu,txsu),(nmt,_)) = Match (ConP nmt (map newVarP [u2..u2+l-1])) (NormalB (applistE (ConE nmu) (map newVarE [u2..u2+l-1]))) [] + where l = length txsu + return $ LamE [newVarP u1] (CaseE (newVarE u1) (map go (zip cxsu cxst))) + where getcxs (DataTx _ _ cxs) = cxs + getcxs _ = error "Thorn doesn't work well, sorry." -unfixdataMutualEx :: - (String,String) -- ^ prefix and suffix of type constructor - -> (String,String) -- ^ prefix and suffix of data constructor - -> (String,String) -- ^ prefix and suffix of infix type constructor - -> (String,String) -- ^ prefix and suffix of infix data constructor - -> [TypeQ] -- ^ data types - -> DecsQ -- ^ declarations of data -unfixdataMutualEx = undefined +-- | +-- Mutually recursive version of 'autohylo'. +autohyloMutual :: + [TypeQ] -- ^ @[u0, .., un]@; @ui@ is a nonrecursive datatype + -> Int -- ^ @k@, index + -> ExpQ -- ^ function with a type @(a0 -> u0 x0 .. xm a0 .. an) -> .. -> (an -> un x0 .. xm a0 .. an) -> (u0 x0 .. xm b0 .. bn -> b0) -> .. -> (un x0 .. xm b0 .. bn -> bn) -> (ak -> bk)@ +autohyloMutual us k = do + ms <- mapM (\u -> u >>= type2typex [] [] >>= applyFixed 0 >>= \(m,DataTx _ _ _) -> return m) us + fms <- mapM autofmap us + u1 <- unique + let n = length us + m i = (ms !! i) - n + f i = mkName ("f"++show (u1+i)) + g i = mkName ("g"++show (u1+i)) + x = newVar u1 + fm i = fms !! i + hylo i = mkName ("hylo"++show i) + hylodef i = ValD (VarP $ hylo i) (NormalB (LamE [VarP x] ( + AppE (VarE $ g i) (applistE (fm i) (replicate (m i) idE ++ map (VarE . hylo) [0..n-1] ++ [AppE (VarE $ f i) (VarE x)])) + ))) [] + return $ LamE (map (VarP . f) [0..n-1] ++ map (VarP . g) [0..n-1]) (LetE (map hylodef [0..n-1]) (VarE $ hylo k)) + {- + \f0 .. fn-1 g0 .. gn-1 -> + let hylo0 = \x -> g0 (fm0 hylo0 .. hylon-1 (f1 x)) + .. + in hylok + -} -autoinMutual :: [TypeQ] -> DecsQ -autoinMutual ts = fail "oh" +-- | +-- @autofoldMutual uts k@ provides a fold for the mutually recursive type @tk@. +autofoldMutual :: + [(TypeQ,TypeQ)] -- ^ @[(u0,t0), .., (un,tn)]@; @ui@ is a nonrecursive datatype and @ti@ is a fixpoint of @ui@ + -> Int -- ^ @k@, index + -> ExpQ -- ^ fold with a type @(u0 x0 .. xm a0 .. an -> a0) -> .. -> (un x0 .. xm a0 .. an -> an) -> (tk x0 .. xm -> ak)@ +autofoldMutual uts k = do + os <- mapM (autooutMutual uts) [0..n-1] + h <- autohyloMutual (map fst uts) k + return $ applistE h os + where n = length uts -autooutMutual :: [TypeQ] -> DecsQ -autooutMutual ts = fail "oh" +-- | +-- @autofoldtypeMutual uts k@ provides the type of @$('autofoldMutual' uts k)@, that is, @(u0 x0 .. xm a0 .. an -> a0) -> .. -> (un x0 .. xm a0 .. an -> an) -> (tk x0 .. xm -> ak)@. +autofoldtypeMutual :: [(TypeQ,TypeQ)] -> Int -> TypeQ +autofoldtypeMutual uts k = do + mtxs <- mapM (\(_,t) -> t >>= type2typex [] [] >>= applyFixed 0) uts + let n = length uts + ms = map fst mtxs + txs = map snd mtxs + t <- typex2type $ txs !! k + uxs <- mapM (\(m,(u,_)) -> u >>= type2typex [] [] >>= applyFixed' m 0) (zip ms uts) + let f i = do + uxa <- applistTx (uxs !! i) (map (VarTx . a) [0..n-1]) + typex2type (ArrowTx uxa (VarTx $ a i)) + a i = mkName ("a"++show i) + x i = mkName ("t"++show i) + fs <- mapM f [0..n-1] + return $ ForallT (map (PlainTV . x) [0..ms!!k-1] ++ map (PlainTV . a) [0..n-1]) [] ( + foldr1 (\t1 t2 -> AppT (AppT ArrowT t1) t2) (fs ++ [t, VarT $ a k])) -autohyloMutual :: [TypeQ] -> DecsQ -autohyloMutual ts = fail "oh" +-- | +-- @autofolddecMutual s uts k@ provides a declaration of a fold for the mutually recursive type @tk@ with the name @s@, with a type signature. +autofolddecMutual :: String -> [(TypeQ,TypeQ)] -> Int -> DecsQ +autofolddecMutual = gendec2 autofoldMutual autofoldtypeMutual -- | --- @autofoldMutual ts@ provides a folding function for the mutually recursive types @ts@. -autofoldMutual :: [TypeQ] -> ExpQ -autofoldMutual ts = do fail "oh" +-- @autounfoldMutual uts k@ provides an unfold for the mutually recursive type @tk@. +autounfoldMutual :: + [(TypeQ,TypeQ)] -- ^ @[(u0,t0), .., (un,tn)]@; @ui@ is a nonrecursive datatype and @ti@ is a fixpoint of @ui@ + -> Int -- ^ @k@, index + -> ExpQ -- ^ unfold with a type @(a0 -> u0 x0 .. xm a0 .. an) -> .. -> (an -> un x0 .. xm a0 .. an) -> (ak -> tk x0 .. xm)@ +autounfoldMutual uts k = do + is <- mapM (autoinMutual uts) [0..n-1] + h <- autohyloMutual (map fst uts) k + u <- unique + return $ LamE (map newFuncP [u..u+n-1]) (applistE h (map newFuncE [u..u+n-1]++is)) + where n = length uts -- | --- @autounfoldMutual ts@ provides an unfolding function for the mutually recursive types @ts@. -autounfoldMutual :: [TypeQ] -> ExpQ -autounfoldMutual ts = do fail "oh" +-- @autounfoldtypeMutual uts k@ provides the type of @$('autounfoldMutual' uts k)@, that is, @(a0 -> u0 x0 .. xm a0 .. an) -> .. -> (an -> un x0 .. xm a0 .. an) -> (ak -> tk x0 .. xm)@. +autounfoldtypeMutual :: [(TypeQ,TypeQ)] -> Int -> TypeQ +autounfoldtypeMutual uts k = do + mtxs <- mapM (\(_,t) -> t >>= type2typex [] [] >>= applyFixed 0) uts + let n = length uts + ms = map fst mtxs + txs = map snd mtxs + t <- typex2type $ txs !! k + uxs <- mapM (\(m,(u,_)) -> u >>= type2typex [] [] >>= applyFixed' m 0) (zip ms uts) + let f i = do + uxa <- applistTx (uxs !! i) (map (VarTx . a) [0..n-1]) + typex2type (ArrowTx (VarTx $ a i) uxa) + a i = mkName ("a"++show i) + x i = mkName ("t"++show i) + fs <- mapM f [0..n-1] + return $ ForallT (map (PlainTV . x) [0..ms!!k-1] ++ map (PlainTV . a) [0..n-1]) [] ( + foldr1 (\t1 t2 -> AppT (AppT ArrowT t1) t2) (fs ++ [VarT $ a k, t])) + +-- | +-- @autounfolddecMutual s uts k@ provides a declaration of an unfold for the mutually recursive type @tk@ with the name @s@, with a type signature. +autounfolddecMutual :: String -> [(TypeQ,TypeQ)] -> Int -> DecsQ +autounfolddecMutual = gendec2 autounfoldMutual autounfoldtypeMutual
− Data/Thorn/FoldExample.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell, TypeOperators #-} - -module Data.Thorn.FoldExample (module Data.Thorn.FoldExample) where - -import Data.Thorn - -data x :$ y = Nil | (x,y) :* (x :$ y) - -unfixdata [t|(:$)|] - -insth = $(autoin [t|(:&$)|] [t|(:$)|]) -outsth = $(autoout [t|(:&$)|] [t|(:$)|]) -hylosth = $(autohylo [t|(:&$)|]) -foldsth = $(autofold [t|(:&$)|] [t|(:$)|]) -unfoldsth = $(autounfold [t|(:&$)|] [t|(:$)|]) -
Data/Thorn/Functor.hs view
@@ -3,47 +3,197 @@ -- | -- The module Data.Thorn.Functor. module Data.Thorn.Functor ( - autofmap + -- * Functors + -- $functor + autofmap, autofmaptype, autofmapdec, autofunctorize + + -- ** Variance , Variance(..) - , autovariance, autofunctorize - ) where + , autovariance + + -- * Examples + + -- ** Basic + -- $basic + + -- ** Functions + -- $function + + -- ** Partial Application + -- $partial + + -- ** Type Synonyms + -- $synonym + + -- ** Variances + -- $variance + + -- ** Recursive Types + -- $recursive + ) where -import Data.Thorn.Type +import Data.Thorn.Internal import Language.Haskell.TH +import Data.Maybe import Data.List import qualified Data.Sequence as S import qualified Data.Foldable as F +import Data.Monoid import Control.Applicative import Control.Monad.State -import Data.Monoid +{- $functor + Thorn generates functors from various kinds of datatypes. + + Quite surprisingly, it still works for any arities, co\/contra\/free\/fixed-variances, partially applied types, type synonyms, and mutual recursions. +-} + +{- $basic + + It's a piece of cake. + +> testtuple :: (Int,String) +> testtuple = $(autofmap [t|(,)|]) (+1) ('h':) (100,"ello") -- (101,"hello") +> +> testeither :: Either Int String +> testeither = $(autofmap [t|Either|]) (+1) ('a':) (Left 100) -- Left 101 +> +> testfunction :: String +> testfunction = $(autofmap [t|(->)|]) ('h':) (++"!") (++", world") "ello" -- "hello, world!" +> +> testlist :: [Int] +> testlist = $(autofmap [t|[]|]) (+10) [1..5] -- [11..15] + +-} + +{- $function + + You can nest functions. + +> data FunFun a b = FunFun ((b -> a) -> b) +> +> varfunfun :: [Variance] +> varfunfun = $(autovariance [t|FunFun|]) -- [Contra,Co] +> +> autofunctorize [t|FunFun|] +> -- instance Profunctor FunFun where +> -- dimap = ... + +-} + +{- $partial + + It works for partially applied types. + +> testpartial :: (Int,Int,Int) +> testpartial = $(autofmap $[t|(,,) Int|]) (+10) (+20) (1,1,1) -- (1,11,21) + + You can use type variants @'T0', 'T1', ..., 'T9'@ to represent any type. + +> testpartial' :: (String,Int,Int) +> testpartial' = $(autofmap $[t|(,,) T0|]) (+10) (+20) ("hello",1,1) -- ("hello",11,21) + +-} + +{- $synonym + +Interestingly, it works for type synonyms. + +> type a :<- b = b -> a +> varnuf :: [Variance] +> varnuf = $(autovariance [t|(:<-)|]) -- [Co,Contra] +> $(autofmapdec "fmapnuf" [t|(:<-)|]) + +-} + +{- $variance + +It works for free-variance and fixed-variance. See how @autofunctorize@ works for free-variance. + +> data What a b c = What1 c (a -> c) | What2 a +> +> varwhat :: [Variance] +> varwhat = $(autovariance [t|What|]) -- [Fixed,Free,Co] +> +> autofunctorize [t|What T0|] +> -- instance Bifunctor (What a) where +> -- bimap = ... +> -- instance Profunctor (What a) where +> -- dimap = ... + +-} + +{- $recursive + +It works for recursive datatypes. + +> data List a = Nil | a :* (List a) deriving Show +> +> autofunctorize [t|List|] +> -- instance Functor List where +> -- fmap = ... +> +> fromNormalList :: [a] -> List a +> fromNormalList [] = Nil +> fromNormalList (a : as) = a :* fromNormalList as +> toNormalList :: List a -> [a] +> toNormalList Nil = [] +> toNormalList (a :* as) = a : toNormalList as +> +> testlist :: [Int] +> testlist = toNormalList $ fmap (+10) (fromNormalList [1..5]) -- [11..15] + +It also works for mutually recursive datatypes. + +> data Rose a = Rose a (Forest a) deriving Show +> data Forest a = Forest [Rose a] deriving Show +> +> autofunctorize [t|Rose|] +> -- instance Functor Rose where +> -- fmap = ... +> +> gorose :: Int -> Rose Int +> gorose 0 = Rose 0 (Forest []) +> gorose n = Rose n (Forest (replicate 2 (gorose (n-1)))) +> testrose :: Rose Int +> testrose = fmap (+10) (gorose 2) +> -- Rose 12 (Forest [Rose 11 (Forest [Rose 10 (Forest []),Rose 10 (Forest [])]),Rose 11 (Forest [Rose 10 (Forest []),Rose 10 (Forest [])])]) + +-} + -- | --- @autofmap t@ generates the @fmap@ of the type @t@. +-- @autofmap t@ generates an fmap of the type @t@. autofmap :: TypeQ -> ExpQ autofmap t = do (n,tx) <- t >>= type2typex [] [] >>= applySpecial 0 u <- unique - (e,txnmes) <- runStateT (autofmap' u tx) [] - return $ LamE (map newFuncP [u..u+n-1]) (LetE (fmap (\(_,nm,Just e') -> ValD (VarP nm) (NormalB e') []) txnmes) e) + (e,(txnmes,bs)) <- runStateT (autofmap' u tx) ([],S.replicate n False) + let txnmes' = filter (\(_,nm,_) -> isJust nm) txnmes + return $ LamE (map (\i -> if S.index bs i then newFuncP (i+u) else WildP) [0..n-1]) (LetE (fmap (\(_,Just nm,Just e') -> ValD (VarP nm) (NormalB e') []) txnmes') e) -autofmap',autofmap'' :: Unique -> Typex -> StateT [(Typex,Name,Maybe Exp)] Q Exp +autofmap',autofmap'' :: Unique -> Typex -> StateT ([(Typex,Maybe Name,Maybe Exp)],S.Seq Bool) Q Exp autofmap' u tx = do - txnmes <- get + (txnmes,bs) <- get case find (\(tx',_,_)->tx==tx') txnmes of - Just (_,nm,_) -> return (VarE nm) + Just (_,Just nm,_) -> return (VarE nm) + Just (_,Nothing,_) -> do + u2 <- unique + let nm = newFmap u2 + put (map (\(tx',nm',e) -> if tx==tx' then (tx,Just nm,e) else (tx',nm',e)) txnmes, bs) + return (VarE nm) Nothing -> autofmap'' u tx -autofmap'' _ (VarTx _) = return $ mkNameE "id" -autofmap'' _ (BasicTx _) = return $ mkNameE "id" -autofmap'' _ (FixedTx _) = return $ mkNameE "id" +autofmap'' _ (VarTx _) = return idE +autofmap'' _ (BasicTx _) = return idE +autofmap'' _ (FixedTx _) = return idE autofmap'' _ NotTx = fail "Thorn doesn't work well, sorry." autofmap'' _ (FuncTx _) = fail "Thorn doesn't accept such a type with a kind * -> k, sorry." autofmap'' u (DataTx nm vmp cxs) = do - txnmes <- get - put ((tx0, newFmap (length txnmes), Nothing) : txnmes) + (txnmes,bs) <- get + put ((tx0,Nothing,Nothing) : txnmes, bs) u2 <- unique e <- LamE [newVarP u2] <$> (CaseE (newVarE u2) <$> (mapM go cxs)) - txnmes' <- get - put $ map (\(tx,nm',e') -> if tx==tx0 then (tx,nm',Just e) else (tx,nm',e')) txnmes' + (txnmes',bs') <- get + put (map (\(tx,nm',e') -> if tx==tx0 then (tx,nm',Just e) else (tx,nm',e')) txnmes', bs') return e where go (nm',txs) = do (u2,es) <- autofmapmap u txs @@ -59,9 +209,12 @@ u2 <- unique return $ LamE [newVarP u2, newVarP (u2+1)] (AppE fb (AppE (newVarE u2) (AppE fa (newVarE (u2+1))))) autofmap'' u (ListTx tx) = autofmap' u tx >>= \f -> return $ AppE (mkNameE "map") f -autofmap'' u (SpecialTx n) = return $ newFuncE (u+n) +autofmap'' u (SpecialTx n) = do + (txnmes,bs) <- get + put (txnmes,S.update n True bs) + return $ newFuncE (u+n) -autofmapmap :: Unique -> [Typex] -> StateT [(Typex,Name,Maybe Exp)] Q (Unique,[Exp]) +autofmapmap :: Unique -> [Typex] -> StateT ([(Typex,Maybe Name,Maybe Exp)],S.Seq Bool) Q (Unique,[Exp]) autofmapmap u txs = do u2 <- unique es <- mapM (\(i,tx) -> autofmap' u tx >>= \e -> return $ AppE e (newVarE i)) (zip [u2..u2+length txs-1] txs) @@ -72,11 +225,11 @@ data Variance = -- | Covariance, one of a normal functor. Co - -- | Contravariance, a dual of covariance. + -- | Contravariance, the dual of covariance. | Contra - -- | Free-variance, or novariance, being supposed to satisfy either covariance or contravariance. + -- | Free-variance, or invariance, being supposed to satisfy either covariance or contravariance. | Free - -- | Fixed-variance, or invariance, being suppoesed to satisfy both covariance and contravariance. + -- | Fixed-variance, or nonvariance, being supposed to satisfy both covariance and contravariance. | Fixed deriving (Show, Read) -- | @v1 `mappend` v2@ means to be supposed to satisfy both @v1@ and @v2@. @@ -142,7 +295,47 @@ autovariance' v dts (ListTx tx) = autovariance' v dts tx -- | --- @autofunctorize t@ provides instance delcarations of the type @t@, for the suitable functor classes : Funtor, Contravariant, Bifunctor, or Profunctor. +-- @autofmaptype t@ provides the type of @$('autofmap' t)@. +autofmaptype :: TypeQ -> TypeQ +autofmaptype t = do + tx <- type2typex [] [] =<< t + vs <- autovarianceRaw t + let ivs = zip [0..length vs-1] vs + a i = mkNameTx ("a"++show i) + b i = mkNameTx ("b"++show i) + c i = mkNameTx ("c"++show i) + a' i = mkName ("a"++show i) + b' i = mkName ("b"++show i) + c' i = mkName ("c"++show i) + gofunc (i,Co) = ArrowTx (a i) (b i) + gofunc (i,Contra) = ArrowTx (b i) (a i) + gofunc (i,Free) = a i + gofunc (i,Fixed) = ArrowTx (a i) (a i) + gosrc (i,Co) = a i + gosrc (i,Contra) = a i + gosrc (i,Free) = b i + gosrc (i,Fixed) = a i + godst (i,Co) = b i + godst (i,Contra) = b i + godst (i,Free) = c i + godst (i,Fixed) = a i + gonm (i,Co) = [a' i,b' i] + gonm (i,Contra) = [a' i,b' i] + gonm (i,Free) = [a' i,b' i,c' i] + gonm (i,Fixed) = [a' i] + tvs = map PlainTV $ concatMap gonm ivs + funcs <- mapM (typex2type . gofunc) ivs + src <- typex2type =<< applistTx tx (map gosrc ivs) + dst <- typex2type =<< applistTx tx (map godst ivs) + return $ ForallT tvs [] (foldr1 (\ta tb -> applistT ArrowT [ta,tb]) (funcs++[src]++[dst])) + +-- | +-- @autofmapdec s t@ provides a declaration of an fmap for the type @t@ with the name @s@, with a type signature. +autofmapdec :: String -> TypeQ -> DecsQ +autofmapdec = gendec1 autofmap autofmaptype + +-- | +-- @autofunctorize t@ provides instance delcarations of the type @t@, for the suitable functor classes : 'Functor', 'Data.Functor.Contravariant.Contravariant', 'Data.Bifunctor.Bifunctor', or 'Data.Profunctor.Profunctor'. Multiple classes can be suitable for @t@, when one of the variances of @t@ is 'Free'. autofunctorize :: TypeQ -> DecsQ autofunctorize t = do vs <- autovarianceRaw t
− Data/Thorn/FunctorExample.hs
@@ -1,59 +0,0 @@-{-# LANGUAGE TemplateHaskell, TypeOperators #-} - -module Data.Thorn.FunctorExample (module Data.Thorn.FunctorExample) where - -import Data.Thorn -import Data.Char -import Data.Functor.Contravariant -import Data.Bifunctor -import Data.Profunctor - -type a :<- b = b -> a -nuf :: Char -nuf = $(autofmap [t|(:<-)|]) chr ord (+1) 'a' -- 'b' -varnuf :: [Variance] -varnuf = $(autovariance [t|(:<-)|]) -- [Co,Contra] - -data Cntr a = Cntr (a -> Int) -autofunctorize [t|Cntr|] -- instance Contravariant Cntr where ... - -tuple :: (Int,Int,Int) -tuple = $(autofmap $[t|(,,) Int|]) (+1) (+2) (0,0,0) -- (0,1,2) -vartuple :: [Variance] -vartuple = $(autovariance [t|(,,) Int|]) -- [Co,Co] - -data FunFun a b = FunFun ((b -> a) -> b) -varfunfun :: [Variance] -varfunfun = $(autovariance [t|FunFun|]) -- [Contra,Co] -autofunctorize [t|FunFun|] -- instance Profunctor FunFun where ... - -data What a b c = What1 c (a -> c) | What2 a -varwhat :: [Variance] -varwhat = $(autovariance [t|What|]) -- [Fixed,Free,Co] -autofunctorize [t|What T0|] --- instance Bifunctor (What a) where ... and --- instance Profunctor (What a) where ... - -data List a = Nil | a :* (List a) deriving Show -fromNormalList :: [a] -> List a -fromNormalList [] = Nil -fromNormalList (a : as) = a :* fromNormalList as -toNormalList :: List a -> [a] -toNormalList Nil = [] -toNormalList (a :* as) = a : toNormalList as -list :: [Int] -list = toNormalList $ $(autofmap [t|List|]) (+10) (fromNormalList [1..5]) -- [11..15] -varlist :: [Variance] -varlist = $(autovariance [t|List|]) -- [Co] -autofunctorize [t|List|] -- instance Functor List where ... - -data Rose a = Rose a (Forest a) deriving Show -data Forest a = Forest [Rose a] deriving Show -gorose n = Rose n (Forest (replicate n (gorose (n-1)))) -rose = $(autofmap [t|Rose|]) (+1) (gorose 2) -varrose, varforest :: [Variance] -varrose = $(autovariance [t|Rose|]) -- [Co] -varforest = $(autovariance [t|Forest|]) -- [Co] -autofunctorize [t|Rose|] -- instance Functor Rose where ... -autofunctorize [t|Forest|] -- instance Functor Forest where ... -
+ Data/Thorn/Internal.hs view
@@ -0,0 +1,292 @@+{-# LANGUAGE TemplateHaskell, EmptyDataDecls #-} + +-- | The module Data.Thorn.Internal. +module Data.Thorn.Internal ( + Unique, unique + , newVar, newSubvar, newFunc, newFmap + , newVarP, newSubvarP, newFuncP, newFmapP + , newVarE, newSubvarE, newFuncE, newFmapE + , mkNameE, mkNameCE, mkNameP, mkNameTx + , idE + , applistE, applistT, applistTx, appTx + , Typex(..) + , Conx + , cxtxs + , type2typex, typex2type, normalizetype + , T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 + , applySpecial, applyFixed, applyFixed' + , gendec1, gendec2 + , modifyname, fixname + ) where + +import Language.Haskell.TH +import Data.Char +import Data.List +import Data.Maybe +import Control.Monad +import Control.Monad.Trans +import Control.Applicative +import System.Random + +instance MonadIO Q where + liftIO = runIO + +type Unique = Int + +unique :: MonadIO m => m Unique +unique = liftIO $ getStdRandom (randomR (0,1000000000)) + +newVar, newSubvar, newFunc, newFmap :: Int -> Name +newVarP, newSubvarP, newFuncP, newFmapP :: Int -> Pat +newVarE, newSubvarE, newFuncE, newFmapE :: Int -> Exp +newVar n = mkName $ "var" ++ show n +newVarP = VarP . newVar +newVarE = VarE . newVar +newSubvar n = mkName $ "subvar" ++ show n +newSubvarP = VarP . newSubvar +newSubvarE = VarE . newSubvar +newFunc n = mkName $ "func" ++ show n +newFuncP = VarP . newFunc +newFuncE = VarE . newFunc +newFmap n = mkName $ "fmap" ++ show n +newFmapP = VarP . newFmap +newFmapE = VarE . newFmap + +mkNameE, mkNameCE :: String -> Exp +mkNameP :: String -> Pat +mkNameTx :: String -> Typex +mkNameE = VarE . mkName +mkNameCE = ConE . mkName +mkNameP = VarP . mkName +mkNameTx = VarTx . mkName + +idE :: Exp +idE = mkNameE "Prelude.id" + +applistE :: Exp -> [Exp] -> Exp +applistT :: Type -> [Type] -> Type +applistTx :: Typex -> [Typex] -> TypexQ +applistE e es = foldl (\e1 e2 -> AppE e1 e2) e es +applistT t ts = foldl (\t1 t2 -> AppT t1 t2) t ts +applistTx tx txs = foldM (\tx1 tx2 -> appTx tx1 tx2) tx txs + +appTx :: Typex -> Typex -> TypexQ +appTx (FuncTx f) tx = f tx +appTx _ _ = fail "appTx : Thorn doesn't work well, sorry." + +data Typex = + VarTx Name + | BasicTx Name + | FixedTx Int + | SpecialTx Int + | NotTx + | FuncTx (Typex -> TypexQ) + | DataTx Name VarMap [Conx] + | SeenDataTx Name VarMap + | TupleTx [Typex] + | ArrowTx Typex Typex + | ListTx Typex +type TypexQ = Q Typex + +type Conx = (Name,[Typex]) + +cxtxs :: Conx -> [Typex] +cxtxs = snd + +type VarMap = [(Name,Typex)] +type Datas = [(Name,VarMap)] + +instance Eq Typex where + VarTx t == VarTx t' = t==t' + BasicTx nm == BasicTx nm' = nm==nm' + SpecialTx n == SpecialTx n' = n==n' + FixedTx n == FixedTx n' = n==n' + NotTx == NotTx = True + DataTx nm vmp cons == DataTx nm' vmp' cons' = nm==nm'&&vmp==vmp'&&cons==cons' + SeenDataTx nm vmp == SeenDataTx nm' vmp' = nm==nm'&&vmp==vmp' + TupleTx txs == TupleTx txs' = txs==txs' + ArrowTx txa txb == ArrowTx txa' txb' = txa==txa'&&txb==txb' + ListTx tx == ListTx tx' = tx==tx' + _ == _ = False + +instance Show Typex where + show (DataTx _ _ _) = "DataTx" + show (SeenDataTx _ _) = "SeenDataTx" + show _ = "Foo" + +type2typex :: VarMap -> Datas -> Type -> TypexQ +type2typex vmp dts (ForallT tvs _ t) = type2typex vmp' dts t + where vmp' = filter (\(nm,_) -> notElem nm (map nameTV tvs)) vmp +type2typex vmp dts (AppT t u) = do + FuncTx f <- type2typex vmp dts t + ux <- type2typex vmp dts u + f ux +type2typex vmp dts (SigT t _) = type2typex vmp dts t +type2typex vmp _ (VarT nm) = case (find (\(nm',_) -> nm==nm') vmp) of + Nothing -> return $ VarTx nm + Just (_,tx) -> return tx +type2typex vmp dts (ConT nm) + | s == "()" = type2typex vmp dts (TupleT 0) + | head s == '(' && dropWhile (==',') (tail s) == ")" = type2typex vmp dts (TupleT (length s - 1)) + | s == "(->)" = type2typex vmp dts ArrowT + | s == "[]" = type2typex vmp dts ListT + | elem s ["Int","Word","Float","Double","Char","Ptr","FunPtr"] = return $ BasicTx nm + | otherwise = reify nm >>= go + where s = nameBase nm + go (TyConI (TySynD _ tvs u)) = ho (length tvs) [] + where ho 0 txs = type2typex (zip (map nameTV tvs) (reverse txs)) dts u + ho n txs = return $ FuncTx $ \tx -> ho (n-1) (tx:txs) + go (TyConI (DataD _ nm' tvs cons _)) = do + b <- istypevariant nm' + if b then tofixed nm' else ho (length tvs) [] + where ho 0 txs = fromData nm' (zip (map nameTV tvs) (reverse txs)) dts cons + ho n txs = return $ FuncTx $ \tx -> ho (n-1) (tx:txs) + go (TyConI (NewtypeD _ _ tvs con _)) = ho (length tvs) [] + where ho 0 txs = fromData nm (zip (map nameTV tvs) (reverse txs)) dts [con] + ho n txs = return $ FuncTx $ \tx -> ho (n-1) (tx:txs) + go (PrimTyConI _ _ _) = fail "type2typex : Thorn doesn't support such primitive types, sorry." + go (FamilyI _ _) = fail "type2typex : Thorn doesn't support type families, sorry." + go _ = fail "type2typex : Thorn doesn't work well, sorry." +type2typex _ _ (TupleT n) = go n [] + where go 0 txs = return $ TupleTx (reverse txs) + go k txs = return $ FuncTx $ \tx -> go (k-1) (tx:txs) +type2typex _ _ ArrowT = return $ FuncTx $ \txa -> return $ FuncTx $ \txb -> return $ ArrowTx txa txb +type2typex _ _ ListT = return $ FuncTx $ \tx -> return $ ListTx tx +type2typex _ _ _ = fail "type2typex : Thorn doesn't support such types, sorry." + +fromData :: Name -> VarMap -> Datas -> [Con] -> TypexQ +fromData nm vmp dts cons = case find (\(nm',_)->nm==nm') dts of + Just (_,vmp') + | vmp == vmp' -> return $ SeenDataTx nm vmp + | otherwise -> fail "fromData : Thorn doesn't support irregular types, sorry." + Nothing -> DataTx nm vmp <$> mapM con2conx cons + where dts' = (nm,vmp) : dts + con2conx (NormalC nm' sts) = (,) nm' <$> mapM stype2typex sts + con2conx (RecC nm' vsts) = (,) nm' <$> mapM vstype2typex vsts + con2conx (InfixC sta nm' stb) = do + txa <- stype2typex sta + txb <- stype2typex stb + return (nm',[txa,txb]) + con2conx (ForallC _ _ _) = fail "fromData : Thorn doesn't support existential types, sorry." + stype2typex (_,t) = type2typex vmp dts' t + vstype2typex (_,_,t) = type2typex vmp dts' t + +nameTV :: TyVarBndr -> Name +nameTV (PlainTV nm) = nm +nameTV (KindedTV nm _) = nm + +typex2type :: Typex -> TypeQ +typex2type (VarTx nm) = return $ VarT nm +typex2type (SpecialTx _) = return StarT +typex2type (FixedTx n) = return $ VarT (mkName $ "t" ++ show n) +typex2type NotTx = return StarT +typex2type (FuncTx f) = do + AppT t StarT <- typex2type =<< f NotTx + return t +typex2type (DataTx nm vmp _) = do + ts <- mapM (typex2type . snd) vmp + return $ applistT (ConT nm) ts +typex2type (SeenDataTx nm vmp) = do + ts <- mapM (typex2type . snd) vmp + return $ applistT (ConT nm) ts +typex2type (BasicTx nm) = return $ ConT nm +typex2type (TupleTx txs) = do + ts <- mapM typex2type txs + return $ applistT (TupleT (length txs)) ts +typex2type (ArrowTx txa txb) = do + ta <- typex2type txa + tb <- typex2type txb + return $ applistT ArrowT [ta,tb] +typex2type (ListTx tx) = do + t <- typex2type tx + return $ AppT ListT t +normalizetype :: Type -> TypeQ +normalizetype t = typex2type =<< type2typex [] [] t + +data T0 +data T1 +data T2 +data T3 +data T4 +data T5 +data T6 +data T7 +data T8 +data T9 + +typevariants :: Q [Name] +typevariants = mapM (\n -> getnm <$> (reify . mkName $ 'T' : show n)) ([0..9] :: [Int]) + where getnm (TyConI (DataD _ nm _ _ _)) = nm + getnm _ = error "typevariants : Thorn doesn't work well, sorry." + +istypevariant :: Name -> Q Bool +istypevariant nm = do + typevariants' <- typevariants + return $ elem nm typevariants' + +tofixed :: Name -> Q Typex +tofixed nm = do + typevariants' <- typevariants + return $ FixedTx (fromJust $ elemIndex nm typevariants') + +applySpecial :: Int -> Typex -> Q (Int,Typex) +applySpecial n (FuncTx f) = f (SpecialTx n) >>= applySpecial (n+1) +applySpecial n tx@(VarTx _) = return (n,tx) +applySpecial n tx@(BasicTx _) = return (n,tx) +applySpecial n tx@(FixedTx _) = return (n,tx) +applySpecial n tx@(SpecialTx _) = return (n,tx) +applySpecial n tx@NotTx = return (n,tx) +applySpecial n tx@(DataTx _ _ _) = return (n,tx) +applySpecial n tx@(SeenDataTx _ _) = return (n,tx) +applySpecial n tx@(TupleTx _) = return (n,tx) +applySpecial n tx@(ArrowTx _ _) = return (n,tx) +applySpecial n tx@(ListTx _) = return (n,tx) + +applyFixed :: Int -> Typex -> Q (Int,Typex) +applyFixed n (FuncTx f) = f (FixedTx n) >>= applyFixed (n+1) +applyFixed n tx@(VarTx _) = return (n,tx) +applyFixed n tx@(BasicTx _) = return (n,tx) +applyFixed n tx@(FixedTx _) = return (n,tx) +applyFixed n tx@(SpecialTx _) = return (n,tx) +applyFixed n tx@NotTx = return (n,tx) +applyFixed n tx@(DataTx _ _ _) = return (n,tx) +applyFixed n tx@(SeenDataTx _ _) = return (n,tx) +applyFixed n tx@(TupleTx _) = return (n,tx) +applyFixed n tx@(ArrowTx _ _) = return (n,tx) +applyFixed n tx@(ListTx _) = return (n,tx) + +applyFixed' :: Int -> Int -> Typex -> TypexQ +applyFixed' k n tx@(FuncTx f) + | k==n = return tx + | otherwise = f (FixedTx n) >>= applyFixed' k (n+1) +applyFixed' _ _ _ = fail "applyFixed' : Thorn doesn't work well, sorry." + +gendec1 :: (a -> ExpQ) -> (a -> TypeQ) -> String -> a -> DecsQ +gendec1 f g s a = do + e <- f a + t <- g a + return [SigD (mkName s) t, ValD (mkNameP s) (NormalB e) []] + +gendec2 :: (a -> b -> ExpQ) -> (a -> b -> TypeQ) -> String -> a -> b -> DecsQ +gendec2 f g s a b = do + e <- f a b + t <- g a b + return [SigD (mkName s) t, ValD (mkNameP s) (NormalB e) []] + +-- | +-- > modifyname ("Prefix","Suffix") ("***","+++") "Hello" == "PrefixHelloSuffix" +-- > modifyname ("Prefix","Suffix") ("***","+++") ":%%%" == ":***%%%+++" +-- > modifyname ("prefix","suffix") ("***","+++") "hello" == "prefixhellosuffix" +-- > modifyname ("prefix","suffix") ("***","+++") "%%%" == "***%%%+++" +modifyname :: (String,String) -> (String,String) -> String -> String +modifyname (pre,suf) (preinfix,sufinfix) s + | isAlpha (head s) = pre ++ s ++ suf + | head s == ':' = ":" ++ preinfix ++ tail s ++ sufinfix + | otherwise = preinfix ++ s ++ sufinfix + +fixname :: (String -> String) -> Name -> Name +fixname f nm + | head s == '(' = mkName (f (init (tail s))) + | otherwise = mkName (f s) + where s = nameBase nm +
− Data/Thorn/Type.hs
@@ -1,241 +0,0 @@-{-# LANGUAGE TemplateHaskell, EmptyDataDecls #-} - --- | The module Data.Thorn.Type. -module Data.Thorn.Type ( - Unique, unique - , newVar, newSubvar, newFunc, newFmap - , newVarP, newSubvarP, newFuncP, newFmapP - , newVarE, newSubvarE, newFuncE, newFmapE - , mkNameE, mkNameCE, mkNameP - , applistE, applistT - , Typex(..) - , Conx(..) - , cxtxs - , type2typex, typex2type, normalizetype - , T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 - , applySpecial, applyFixed - ) where - -import Language.Haskell.TH -import Data.List -import Data.Maybe -import Control.Monad.Trans -import Control.Applicative -import System.Random - -instance MonadIO Q where - liftIO = runIO - -type Unique = Int - -unique :: MonadIO m => m Unique -unique = liftIO $ getStdRandom (randomR (0,1000000000)) - -newVar, newSubvar, newFunc, newFmap :: Int -> Name -newVarP, newSubvarP, newFuncP, newFmapP :: Int -> Pat -newVarE, newSubvarE, newFuncE, newFmapE :: Int -> Exp -newVar n = mkName $ "var" ++ show n -newVarP = VarP . newVar -newVarE = VarE . newVar -newSubvar n = mkName $ "subvar" ++ show n -newSubvarP = VarP . newSubvar -newSubvarE = VarE . newSubvar -newFunc n = mkName $ "func" ++ show n -newFuncP = VarP . newFunc -newFuncE = VarE . newFunc -newFmap n = mkName $ "fmap" ++ show n -newFmapP = VarP . newFmap -newFmapE = VarE . newFmap - -mkNameE, mkNameCE :: String -> Exp -mkNameP :: String -> Pat -mkNameE = VarE . mkName -mkNameCE = ConE . mkName -mkNameP = VarP . mkName - -applistE :: Exp -> [Exp] -> Exp -applistT :: Type -> [Type] -> Type -applistE e es = foldl (\e' es' -> AppE e' es') e es -applistT t ts = foldl (\t' ts' -> AppT t' ts') t ts - -data Typex = - VarTx Name - | BasicTx Name - | FixedTx Int - | SpecialTx Int - | NotTx - | FuncTx (Typex -> TypexQ) - | DataTx Name VarMap [Conx] - | SeenDataTx Name VarMap - | TupleTx [Typex] - | ArrowTx Typex Typex - | ListTx Typex -type TypexQ = Q Typex - -type Conx = (Name,[Typex]) - -cxtxs :: Conx -> [Typex] -cxtxs = snd - -type VarMap = [(Name,Typex)] -type Datas = [(Name,VarMap)] - -instance Eq Typex where - VarTx t == VarTx t' = t==t' - BasicTx nm == BasicTx nm' = nm==nm' - SpecialTx n == SpecialTx n' = n==n' - FixedTx n == FixedTx n' = n==n' - NotTx == NotTx = True - DataTx nm vmp cons == DataTx nm' vmp' cons' = nm==nm'&&vmp==vmp'&&cons==cons' - SeenDataTx nm vmp == SeenDataTx nm' vmp' = nm==nm'&&vmp==vmp' - TupleTx txs == TupleTx txs' = txs==txs' - ArrowTx txa txb == ArrowTx txa' txb' = txa==txa'&&txb==txb' - ListTx tx == ListTx tx' = tx==tx' - _ == _ = False - -instance Show Typex where - show (DataTx _ _ _) = "DataTx" - show (SeenDataTx _ _) = "SeenDataTx" - show _ = "Foo" - -type2typex :: VarMap -> Datas -> Type -> TypexQ -type2typex vmp dts (ForallT tvs _ t) = type2typex vmp' dts t - where vmp' = filter (\(nm,_) -> notElem nm (map nameTV tvs)) vmp -type2typex vmp dts (AppT t u) = do - FuncTx f <- type2typex vmp dts t - ux <- type2typex vmp dts u - f ux -type2typex vmp dts (SigT t _) = type2typex vmp dts t -type2typex vmp _ (VarT nm) = case (find (\(nm',_) -> nm==nm') vmp) of - Nothing -> return $ VarTx nm - Just (_,tx) -> return tx -type2typex vmp dts (ConT nm) - | s == "()" = type2typex vmp dts (TupleT 0) - | head s == '(' && dropWhile (==',') (tail s) == ")" = type2typex vmp dts (TupleT (length s - 1)) - | s == "(->)" = type2typex vmp dts ArrowT - | s == "[]" = type2typex vmp dts ListT - | elem s ["Int","Word","Float","Double","Char","Ptr","FunPtr"] = return $ BasicTx nm - | otherwise = reify nm >>= go - where s = nameBase nm - go (TyConI (TySynD _ tvs u)) = ho (length tvs) [] - where ho 0 txs = type2typex (zip (map nameTV tvs) (reverse txs)) dts u - ho n txs = return $ FuncTx $ \tx -> ho (n-1) (tx:txs) - go (TyConI (DataD _ nm' tvs cons _)) = do - b <- istypevariant nm' - if b then tofixed nm' else ho (length tvs) [] - where ho 0 txs = fromData nm' (zip (map nameTV tvs) (reverse txs)) dts cons - ho n txs = return $ FuncTx $ \tx -> ho (n-1) (tx:txs) - go (TyConI (NewtypeD _ _ tvs con _)) = ho (length tvs) [] - where ho 0 txs = fromData nm (zip (map nameTV tvs) (reverse txs)) dts [con] - ho n txs = return $ FuncTx $ \tx -> ho (n-1) (tx:txs) - go (PrimTyConI _ _ _) = fail "Thorn doesn't support such primitive types, sorry." - go (FamilyI _ _) = fail "Thorn doesn't support type families, sorry." - go _ = fail "Thorn doesn't work well, sorry." -type2typex _ _ (TupleT n) = go n [] - where go 0 txs = return $ TupleTx (reverse txs) - go k txs = return $ FuncTx $ \tx -> go (k-1) (tx:txs) -type2typex _ _ ArrowT = return $ FuncTx $ \txa -> return $ FuncTx $ \txb -> return $ ArrowTx txa txb -type2typex _ _ ListT = return $ FuncTx $ \tx -> return $ ListTx tx -type2typex _ _ _ = fail "Thorn doesn't support such types, sorry." - -fromData :: Name -> VarMap -> Datas -> [Con] -> TypexQ -fromData nm vmp dts cons = case find (\(nm',_)->nm==nm') dts of - Just (_,vmp') - | vmp == vmp' -> return $ SeenDataTx nm vmp - | otherwise -> fail "Thorn doesn't support irregular types, sorry." - Nothing -> DataTx nm vmp <$> mapM con2conx cons - where dts' = (nm,vmp) : dts - con2conx (NormalC nm' sts) = (,) nm' <$> mapM stype2typex sts - con2conx (RecC nm' vsts) = (,) nm' <$> mapM vstype2typex vsts - con2conx (InfixC sta nm' stb) = do - txa <- stype2typex sta - txb <- stype2typex stb - return (nm',[txa,txb]) - con2conx (ForallC _ _ _) = fail "Thorn doesn't support existential types, sorry." - stype2typex (_,t) = type2typex vmp dts' t - vstype2typex (_,_,t) = type2typex vmp dts' t - -nameTV :: TyVarBndr -> Name -nameTV (PlainTV nm) = nm -nameTV (KindedTV nm _) = nm - -typex2type :: Typex -> TypeQ -typex2type (VarTx nm) = return $ VarT nm -typex2type (SpecialTx _) = return StarT -typex2type (FixedTx n) = return $ VarT (mkName $ "t" ++ show n) -typex2type NotTx = return StarT -typex2type (FuncTx f) = do - AppT t StarT <- typex2type =<< f NotTx - return t -typex2type (DataTx nm vmp _) = do - ts <- mapM (typex2type . snd) vmp - return $ applistT (ConT nm) ts -typex2type (SeenDataTx nm vmp) = do - ts <- mapM (typex2type . snd) vmp - return $ applistT (ConT nm) ts -typex2type (BasicTx nm) = return $ ConT nm -typex2type (TupleTx txs) = do - ts <- mapM typex2type txs - return $ applistT (TupleT (length txs)) ts -typex2type (ArrowTx txa txb) = do - ta <- typex2type txa - tb <- typex2type txb - return $ applistT ArrowT [ta,tb] -typex2type (ListTx tx) = do - t <- typex2type tx - return $ AppT ListT t -normalizetype :: Type -> TypeQ -normalizetype t = typex2type =<< type2typex [] [] t - -data T0 -data T1 -data T2 -data T3 -data T4 -data T5 -data T6 -data T7 -data T8 -data T9 - -typevariants :: Q [Name] -typevariants = mapM (\n -> getnm <$> (reify . mkName $ 'T' : show n)) ([0..9] :: [Int]) - where getnm (TyConI (DataD _ nm _ _ _)) = nm - getnm _ = error "Thorn doesn't work well, sorry." - -istypevariant :: Name -> Q Bool -istypevariant nm = do - typevariants' <- typevariants - return $ elem nm typevariants' - -tofixed :: Name -> Q Typex -tofixed nm = do - typevariants' <- typevariants - return $ FixedTx (fromJust $ elemIndex nm typevariants') - -applySpecial :: Int -> Typex -> Q (Int,Typex) -applySpecial n (FuncTx f) = f (SpecialTx n) >>= applySpecial (n+1) -applySpecial n tx@(VarTx _) = return (n,tx) -applySpecial n tx@(BasicTx _) = return (n,tx) -applySpecial n tx@(FixedTx _) = return (n,tx) -applySpecial n tx@(SpecialTx _) = return (n,tx) -applySpecial n tx@NotTx = return (n,tx) -applySpecial n tx@(DataTx _ _ _) = return (n,tx) -applySpecial n tx@(SeenDataTx _ _) = return (n,tx) -applySpecial n tx@(TupleTx _) = return (n,tx) -applySpecial n tx@(ArrowTx _ _) = return (n,tx) -applySpecial n tx@(ListTx _) = return (n,tx) - -applyFixed :: Int -> Typex -> Q (Int,Typex) -applyFixed n (FuncTx f) = f (FixedTx n) >>= applyFixed (n+1) -applyFixed n tx@(VarTx _) = return (n,tx) -applyFixed n tx@(BasicTx _) = return (n,tx) -applyFixed n tx@(FixedTx _) = return (n,tx) -applyFixed n tx@(SpecialTx _) = return (n,tx) -applyFixed n tx@NotTx = return (n,tx) -applyFixed n tx@(DataTx _ _ _) = return (n,tx) -applyFixed n tx@(SeenDataTx _ _) = return (n,tx) -applyFixed n tx@(TupleTx _) = return (n,tx) -applyFixed n tx@(ArrowTx _ _) = return (n,tx) -applyFixed n tx@(ListTx _) = return (n,tx) -
thorn.cabal view
@@ -1,8 +1,17 @@ name: thorn synopsis: Datatype Manipulation with Template Haskell-description: Datatype Manipulation with Template Haskell+description:+ Thorn generates+ .+ * functors from various kinds of datatypes, regardless of arity or variances.+ .+ * folds and unfolds from various kinds of recursive datatypes, including mutually recursive ones.+ .+ A single function of Thorn will give you a lot. Just try it.+ .+ The haddock is here. <http://kinokkory.github.io/Thorn/> category: Data, Generics-version: 0.1.0.3+version: 0.2 stability: experimental license: BSD3 license-file: LICENSE@@ -19,8 +28,8 @@ location: git://github.com/Kinokkory/Thorn.git library- exposed-modules: Data.Thorn, Data.Thorn.FunctorExample, Data.Thorn.FoldExample- other-modules: Data.Thorn.Functor, Data.Thorn.Fold, Data.Thorn.Type+ exposed-modules: Data.Thorn, Data.Thorn.Functor, Data.Thorn.Fold, Data.Thorn.Basic+ other-modules: Data.Thorn.Internal build-depends: base >= 4 && < 5, random > 1,