summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbringert <bringert@cs.chalmers.se>2007-10-20 18:42:16 +0000
committerbringert <bringert@cs.chalmers.se>2007-10-20 18:42:16 +0000
commit173d0ae876371a2156a34d30b781c43a54f121ae (patch)
treea98d69435a7fa227d7128fc21721d79f4a56a556 /src
parent484c4ef336617fc1e817ef168757d9f4d1abdcdb (diff)
Added Compos instance generation to the haskell_gadt printer. Added GF.Data.Compos module which is imported by the code generated by haskell_gadt.
Diffstat (limited to 'src')
-rw-r--r--src/GF/API/GrammarToHaskell.hs33
-rw-r--r--src/GF/Data/Compos.hs37
2 files changed, 69 insertions, 1 deletions
diff --git a/src/GF/API/GrammarToHaskell.hs b/src/GF/API/GrammarToHaskell.hs
index c8728bada..1325ae52c 100644
--- a/src/GF/API/GrammarToHaskell.hs
+++ b/src/GF/API/GrammarToHaskell.hs
@@ -23,6 +23,7 @@ import GF.Infra.Modules
import GF.Data.Operations
import Data.List (isPrefixOf, find, intersperse)
+import Data.Maybe (fromMaybe)
-- | the main function
grammar2haskell :: GFC.CanonGrammar -> String
@@ -33,7 +34,7 @@ grammar2haskell gr = foldr (++++) [] $
grammar2haskellGADT :: GFC.CanonGrammar -> String
grammar2haskellGADT gr = foldr (++++) [] $
["{-# OPTIONS_GHC -fglasgow-exts #-}"] ++
- haskPreamble ++ [datatypesGADT gr', gfinstances gr', fginstances gr']
+ haskPreamble ++ [datatypesGADT gr', composInstance gr', gfinstances gr', fginstances gr']
where gr' = hSkeleton gr
-- | by this you can prefix all identifiers with stg; the default is 'G'
@@ -48,7 +49,11 @@ haskPreamble =
"import GF.Grammar.Grammar",
"import GF.Grammar.PrGrammar",
"import GF.Grammar.Macros",
+ "import GF.Data.Compos",
"import GF.Data.Operations",
+ "",
+ "import Control.Applicative (pure,(<*>))",
+ "import Data.Traversable (traverse)",
"----------------------------------------------------",
"-- automatic translation from GF to Haskell",
"----------------------------------------------------",
@@ -174,6 +179,32 @@ fInstance m (cat,rules) =
gId f +++
prTList " " [prParenth ("fg" +++ x) | x <- vars]
+composInstance :: (String,HSkeleton) -> String
+composInstance (_,skel) = unlines $
+ ["instance Compos Tree where",
+ " compos f t = case t of"]
+ ++ map (" "++) (concatMap prComposCat skel
+ ++ if not allRecursive then ["_ -> pure t"] else [])
+ where
+ prComposCat c@(cat, fs)
+ | isListCat c = [gId cat +++ "xs" +++ "->"
+ +++ "pure" +++ gId cat +++ "<*> traverse f" +++ "xs"]
+ | otherwise = concatMap (prComposFun cat) fs
+ prComposFun :: OIdent -> (OIdent,[OIdent]) -> [String]
+ prComposFun cat c@(fun,args)
+ | any isTreeType args = [gId fun +++ unwords vars +++ "->" +++ rhs]
+ | otherwise = []
+ where vars = ["x" ++ show n | n <- [1..length args]]
+ rhs = "pure" +++ gId fun +++ unwords (zipWith prRec vars args)
+ where prRec var typ
+ | not (isTreeType typ) = "<*>" +++ "pure" +++ var
+ | otherwise = "<*>" +++ "f" +++ var
+ allRecursive = and [any isTreeType args | (_,fs) <- skel, (_,args) <- fs]
+ isTreeType cat = cat `elem` (map fst skel ++ builtin)
+ isList cat = case filter ((==cat) . fst) skel of
+ [] -> error $ "Unknown cat " ++ show cat
+ x:_ -> isListCat x
+ builtin = ["GString", "GInt", "GFloat"]
hSkeleton :: GFC.CanonGrammar -> (String,HSkeleton)
hSkeleton gr = (name,collectR rules [(c,[]) | c <- cats]) where
diff --git a/src/GF/Data/Compos.hs b/src/GF/Data/Compos.hs
new file mode 100644
index 000000000..f8e592bc1
--- /dev/null
+++ b/src/GF/Data/Compos.hs
@@ -0,0 +1,37 @@
+{-# OPTIONS_GHC -fglasgow-exts #-}
+module GF.Data.Compos (Compos(..),composOp,composM,composM_,composFold) where
+
+import Control.Applicative (Applicative(..), Const(..), WrappedMonad(..))
+import Data.Monoid (Monoid(..))
+
+class Compos t where
+ compos :: Applicative f => (forall a. t a -> f (t a)) -> t c -> f (t c)
+
+composOp :: Compos t => (forall a. t a -> t a) -> t c -> t c
+composOp f = runIdentity . compos (Identity . f)
+
+composFold :: (Monoid o, Compos t) => (forall a. t a -> o) -> t c -> o
+composFold f = getConst . compos (Const . f)
+
+composM :: (Compos t, Monad m) => (forall a. t a -> m (t a)) -> t c -> m (t c)
+composM f = unwrapMonad . compos (WrapMonad . f)
+
+composM_ :: (Compos t, Monad m) => (forall a. t a -> m ()) -> t c -> m ()
+composM_ f = unwrapMonad_ . composFold (WrapMonad_ . f)
+
+
+newtype Identity a = Identity { runIdentity :: a }
+
+instance Functor Identity where
+ fmap f (Identity x) = Identity (f x)
+
+instance Applicative Identity where
+ pure = Identity
+ Identity f <*> Identity x = Identity (f x)
+
+
+newtype WrappedMonad_ m = WrapMonad_ { unwrapMonad_ :: m () }
+
+instance Monad m => Monoid (WrappedMonad_ m) where
+ mempty = WrapMonad_ (return ())
+ WrapMonad_ x `mappend` WrapMonad_ y = WrapMonad_ (x >> y) \ No newline at end of file