multirec 0.1 → 0.2
raw patch · 23 files changed
+1251/−84 lines, 23 filesdep +template-haskell
Dependencies added: template-haskell
Files
- LICENSE +1/−1
- examples/AST.hs +2/−51
- examples/ASTExamples.hs +64/−17
- examples/ASTTHUse.hs +33/−0
- examples/ASTUse.hs +104/−0
- examples/Single.hs +16/−0
- examples/SingleExamples.hs +21/−0
- examples/SingleTHUse.hs +26/−0
- examples/SingleUse.hs +87/−0
- multirec.cabal +19/−4
- src/Generics/MultiRec/Base.hs +21/−2
- src/Generics/MultiRec/Compos.hs +2/−1
- src/Generics/MultiRec/ConNames.hs +54/−0
- src/Generics/MultiRec/Constructor.hs +38/−0
- src/Generics/MultiRec/Eq.hs +10/−2
- src/Generics/MultiRec/Fold.hs +45/−5
- src/Generics/MultiRec/FoldAlg.hs +128/−0
- src/Generics/MultiRec/FoldAlgK.hs +127/−0
- src/Generics/MultiRec/FoldK.hs +93/−0
- src/Generics/MultiRec/HFix.hs +34/−0
- src/Generics/MultiRec/HFunctor.hs +7/−1
- src/Generics/MultiRec/Show.hs +80/−0
- src/Generics/MultiRec/TH.hs +239/−0
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2008 Universiteit Utrecht+Copyright (c) 2008--2009 Universiteit Utrecht All rights reserved.
examples/AST.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE EmptyDataDecls #-} module AST where @@ -22,58 +23,8 @@ data Decl = Var := Expr | Seq Decl Decl+ | None deriving Show type Var = String---- * Instantiating the library for AST --data AST :: * -> * where- Expr :: AST Expr- Decl :: AST Decl- Var :: AST Var--type instance PF AST = - K Int :>: Expr -- |Const|- :+: (I Expr :*: I Expr) :>: Expr -- |Add|- :+: (I Expr :*: I Expr) :>: Expr -- |Mul|- :+: I Var :>: Expr -- |EVar|- :+: (I Decl :*: I Expr) :>: Expr -- |Let|- :+: (I Var :*: I Expr) :>: Decl -- |:=|- :+: (I Decl :*: I Decl) :>: Decl -- |Seq|- :+: K String :>: Var -- |V|--instance Ix AST Expr where-- from_ (Const i) = L (Tag (K i))- from_ (Add e f) = R (L (Tag (I (I0 e) :*: I (I0 f))))- from_ (Mul e f) = R (R (L (Tag (I (I0 e) :*: I (I0 f)))))- from_ (EVar x) = R (R (R (L (Tag (I (I0 x))))))- from_ (Let d e) = R (R (R (R (L (Tag (I (I0 d) :*: I (I0 e)))))))-- to_ (L (Tag (K i))) = Const i- to_ (R (L (Tag (I (I0 e) :*: I (I0 f))))) = Add e f- to_ (R (R (L (Tag (I (I0 e) :*: I (I0 f)))))) = Mul e f- to_ (R (R (R (L (Tag (I (I0 x))))))) = EVar x- to_ (R (R (R (R (L (Tag (I (I0 d) :*: I (I0 e)))))))) = Let d e- - index = Expr--instance Ix AST Decl where-- from_ (x := e) = R (R (R (R (R (L (Tag (I (I0 x) :*: I (I0 e))))))))- from_ (Seq c d) = R (R (R (R (R (R (L (Tag (I (I0 c) :*: I (I0 d)))))))))-- to_ (R (R (R (R (R (L (Tag (I (I0 x) :*: I (I0 e))))))))) = x := e- to_ (R (R (R (R (R (R (L (Tag (I (I0 c) :*: I (I0 d))))))))))= Seq c d-- index = Decl--instance Ix AST Var where-- from_ x = R (R (R (R (R (R (R(Tag (K x))))))))-- to_ (R (R (R (R (R (R (R(Tag (K x))))))))) = x-- index = Var
examples/ASTExamples.hs view
@@ -7,16 +7,23 @@ import Control.Arrow ((>>>)) import Control.Monad ((>=>)) +-- Replace ASTUse with ASTTHUse below if you want+-- to test TH code generation. import AST+import ASTUse+-- import ASTTHUse import Generics.MultiRec.Base import Generics.MultiRec.Compos-import Generics.MultiRec.Fold+import qualified Generics.MultiRec.Fold as F+import Generics.MultiRec.Fold (con, tag)+import Generics.MultiRec.FoldAlg as FA import Generics.MultiRec.Eq+import Generics.MultiRec.Show as GS -- | Example expression -example = Let ("x" := Mul (Const 6) (Const 9))+example = Let (Seq ("x" := Mul (Const 6) (Const 9)) None) (Add (EVar "x") (EVar "y")) -- | Renaming variables using 'compos'@@ -44,27 +51,62 @@ -- | Algebra for evaluating an expression -evalAlgebra :: Algebra AST Value-evalAlgebra _ = - tag (\ (K x) -> EV (const x))- & tag (\ (I (EV x) :*: I (EV y)) -> EV (\ env -> x env + y env))- & tag (\ (I (EV x) :*: I (EV y)) -> EV (\ env -> x env * y env))- & tag (\ (I (VV x)) -> EV (fromJust . lookup x))- & tag (\ (I (DV e) :*: I (EV x)) -> EV (\ env -> x (e env)))- & tag (\ (I (VV x) :*: I (EV v)) -> DV (\ env -> (x, v env) : env ))- & tag (\ (I (DV f) :*: I (DV g)) -> DV (g . f))- & tag (\ (K x) -> VV x)+infixr 5 &. +(&.) = (F.&)++evalAlgebra1 :: F.Algebra AST Value+evalAlgebra1 _ = + + tag ( con (\ (K x) -> EV (const x))+ &. con (\ (I (EV x) :*: I (EV y)) -> EV (\ env -> x env + y env))+ &. con (\ (I (EV x) :*: I (EV y)) -> EV (\ env -> x env * y env))+ &. con (\ (I (VV x)) -> EV (fromJust . lookup x))+ &. con (\ (I (DV e) :*: I (EV x)) -> EV (\ env -> x (e env)))+ )+ &. tag ( con (\ (I (VV x) :*: I (EV v)) -> DV (\ env -> (x, v env) : env ))+ &. con (\ (I (DV f) :*: I (DV g)) -> DV (g . f))+ &. con (\ U -> DV id)+ )+ &. tag (\ (K x) -> VV x)++-- | More convenient algebra for evaluating an expression++evalAlgebra2 :: FA.Algebra AST Value+evalAlgebra2 _ =++ ( (\ x -> EV (const x))+ & (\ (EV x) (EV y) -> EV (\ env -> x env + y env))+ & (\ (EV x) (EV y) -> EV (\ env -> x env * y env))+ & (\ (VV x) -> EV (fromJust . lookup x))+ & (\ (DV e) (EV x) -> EV (\ env -> x (e env)))+ )+ & ( (\ (VV x) (EV v) -> DV (\ env -> (x, v env) : env ))+ & (\ (DV f) (DV g) -> DV (g . f))+ & ( DV id)+ )+ & (\ x -> VV x)+ -- | Evaluator -eval :: Expr -> Env -> Int-eval x = let (EV f) = fold evalAlgebra x in f+eval1 :: Expr -> Env -> Int+eval1 x = let (EV f) = F.fold evalAlgebra1 x in f --- | Test for 'eval'+-- | Evaluator -testEval :: Int-testEval = eval example [("y", -12)] +eval2 :: Expr -> Env -> Int+eval2 x = let (EV f) = FA.fold evalAlgebra2 x in f +-- | Test for 'eval1'++testEval1 :: Int+testEval1 = eval1 example [("y", -12)] ++-- | Test for 'eval2'++testEval2 :: Int+testEval2 = eval2 example [("y", -12)] + -- | Equality instance for 'Expr' instance Eq Expr where@@ -74,3 +116,8 @@ testEq :: (Bool, Bool) testEq = (example == example, example == testRename)++-- | Test for generic show++testShow :: IO ()+testShow = putStrLn $ GS.show Expr example
+ examples/ASTTHUse.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE TemplateHaskell #-}++module ASTTHUse where++import Generics.MultiRec.Base+import Generics.MultiRec.TH+import AST++-- * Instantiating the library for AST using TH++-- ** Index type++data AST :: * -> * where+ Expr :: AST Expr+ Decl :: AST Decl+ Var :: AST Var++-- ** Constructors++$(deriveConstructors [''Expr, ''Decl, ''Var])++-- ** Functor encoding and 'Ix' instances++$(deriveSystem ''AST [''Expr, ''Decl, ''Var] "PFAST")+type instance PF AST = PFAST+
+ examples/ASTUse.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE EmptyDataDecls #-}++module ASTUse where++import Generics.MultiRec.Base+import AST++-- * Instantiating the library for AST ++-- ** Index type++data AST :: * -> * where+ Expr :: AST Expr+ Decl :: AST Decl+ Var :: AST Var++-- ** Constructors++data Const+instance Constructor Const where conName _ = "Const"+data Add+instance Constructor Add where conName _ = "Add"+data Mul+instance Constructor Mul where conName _ = "Mul"+data EVar+instance Constructor EVar where conName _ = "EVar"+data Let+instance Constructor Let where conName _ = "Let"+data Assign+instance Constructor Assign where+ conName _ = ":="+ conFixity _ = Infix NotAssociative 1+data Seq+instance Constructor Seq where conName _ = "Seq"+data None+instance Constructor None where conName _ = "None"++-- ** Functor encoding++-- Variations of the encoding below are possible. For instance,+-- the 'C' applications can be omitted if no functions that require+-- constructor information are needed. Furthermore, it is possible+-- to tag every constructor rather than every datatype. That makes+-- the overall structure slightly simpler, but makes the nesting+-- of 'L' and 'R' constructors larger in turn.++type instance PF AST = + ( C Const (K Int)+ :+: C Add (I Expr :*: I Expr)+ :+: C Mul (I Expr :*: I Expr)+ :+: C EVar (I Var)+ :+: C Let (I Decl :*: I Expr)+ ) :>: Expr+ :+: ( C Assign (I Var :*: I Expr)+ :+: C Seq (I Decl :*: I Decl)+ :+: C None U+ ) :>: Decl+ :+: ( (K String)+ ) :>: Var++-- ** 'Ix' instances++instance Ix AST Expr where++ from_ (Const i) = L (Tag (L (C (K i))))+ from_ (Add e f) = L (Tag (R (L (C (I (I0 e) :*: I (I0 f))))))+ from_ (Mul e f) = L (Tag (R (R (L (C (I (I0 e) :*: I (I0 f)))))))+ from_ (EVar x) = L (Tag (R (R (R (L (C (I (I0 x))))))))+ from_ (Let d e) = L (Tag (R (R (R (R (C (I (I0 d) :*: I (I0 e))))))))++ to_ (L (Tag (L (C (K i))))) = Const i+ to_ (L (Tag (R (L (C (I (I0 e) :*: I (I0 f))))))) = Add e f+ to_ (L (Tag (R (R (L (C (I (I0 e) :*: I (I0 f)))))))) = Mul e f+ to_ (L (Tag (R (R (R (L (C (I (I0 x))))))))) = EVar x+ to_ (L (Tag (R (R (R (R (C (I (I0 d) :*: I (I0 e))))))))) = Let d e++ index = Expr++instance Ix AST Decl where++ from_ (x := e) = R (L (Tag (L (C (I (I0 x) :*: I (I0 e))))))+ from_ (Seq c d) = R (L (Tag (R (L (C (I (I0 c) :*: I (I0 d)))))))+ from_ (None) = R (L (Tag (R (R (C U)))))++ to_ (R (L (Tag (L (C (I (I0 x) :*: I (I0 e))))))) = x := e+ to_ (R (L (Tag (R (L (C (I (I0 c) :*: I (I0 d)))))))) = Seq c d+ to_ (R (L (Tag (R (R (C U)))))) = None++ index = Decl++instance Ix AST Var where++ from_ x = R (R (Tag (K x)))++ to_ (R (R (Tag (K x)))) = x++ index = Var+
+ examples/Single.hs view
@@ -0,0 +1,16 @@+module Single where++import Generics.MultiRec.Base+++-- * A single datatype++data Logic = Var String+ | Logic :->: Logic -- implication+ | Logic :<->: Logic -- equivalence+ | Logic :&&: Logic -- and (conjunction)+ | Logic :||: Logic -- or (disjunction)+ | Not Logic -- not+ | T -- true+ | F -- false+ deriving (Show, Eq, Ord)
+ examples/SingleExamples.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE FlexibleContexts #-}++module SingleExamples where++import Generics.MultiRec.Base+import Generics.MultiRec.FoldAlgK++-- Replace SingleUse with SingleTHUse below if you want+-- to test TH code generation.+import SingleUse+import Single++-- | evalLogic takes a function that gives a logic values to variables,+-- | and a Logic expression, and evaluates it.+evalLogic :: (String -> Bool) -> Logic -> Bool+evalLogic env = fold algebra + where+ algebra :: Algebra LogicF Bool+ algebra _ = env & impl & (==) & (&&) & (||) & not & True & False++ impl p q = not p || q
+ examples/SingleTHUse.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module SingleTHUse where++import Single+import Generics.MultiRec.Base+import Generics.MultiRec.TH+++-- * Instantiating multirec for Logic using TH+-- ** Index type+data LogicF :: * -> * where+ Logic :: LogicF Logic++-- ** Constructors+$(deriveConstructors [''Logic])++-- ** Functor encoding and 'Ix' instances+$(deriveSystem ''LogicF [''Logic] "PFLogic")+type instance PF LogicF = PFLogic
+ examples/SingleUse.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module SingleUse where++import Generics.MultiRec.Base+import Single++-- * Instantiating the library for Logic ++-- ** Index type++data LogicF :: * -> * where+ Logic :: LogicF Logic++-- ** Constructors++data Var+instance Constructor Var where conName _ = "Var"++data Impl+instance Constructor Impl where+ conName _ = ":->:"+ conFixity _ = Infix RightAssociative 2++data Equiv+instance Constructor Equiv where+ conName _ = ":<->:"+ conFixity _ = Infix RightAssociative 1++data And+instance Constructor And where+ conName _ = ":&&:"+ conFixity _ = Infix RightAssociative 4++data Or+instance Constructor Or where+ conName _ = ":||:"+ conFixity _ = Infix RightAssociative 3++data Not+instance Constructor Not where conName _ = "Not"+data T+instance Constructor T where conName _ = "T"+data F+instance Constructor F where conName _ = "F"++-- ** Functor encoding++type instance PF LogicF = + ( C Var (K String)+ :+: C Impl (I Logic :*: I Logic)+ :+: C Equiv (I Logic :*: I Logic)+ :+: C And (I Logic :*: I Logic)+ :+: C Or (I Logic :*: I Logic)+ :+: C Not (I Logic)+ :+: C T U+ :+: C F U+ ) :>: Logic++-- ** 'Ix' instances++instance Ix LogicF Logic where++ from_ (Var s) = Tag (L (C (K s)))+ from_ (l1 :->: l2) = Tag (R (L (C (I (I0 l1) :*: I (I0 l2)))))+ from_ (l1 :<->: l2) = Tag (R (R (L (C (I (I0 l1) :*: I (I0 l2))))))+ from_ (l1 :&&: l2) = Tag (R (R (R (L (C (I (I0 l1) :*: I (I0 l2)))))))+ from_ (l1 :||: l2) = Tag (R (R (R (R (L (C (I (I0 l1) :*: I (I0 l2))))))))+ from_ (Not l) = Tag (R (R (R (R (R (L (C (I (I0 l)))))))))+ from_ T = Tag (R (R (R (R (R (R (L (C U))))))))+ from_ F = Tag (R (R (R (R (R (R (R (C U))))))))++ to_ (Tag (L (C (K s)))) = Var s+ to_ (Tag (R (L (C (I (I0 l1) :*: I (I0 l2)))))) = l1 :->: l2+ to_ (Tag (R (R (L (C (I (I0 l1) :*: I (I0 l2))))))) = l1 :<->: l2+ to_ (Tag (R (R (R (L (C (I (I0 l1) :*: I (I0 l2)))))))) = l1 :&&: l2+ to_ (Tag (R (R (R (R (L (C (I (I0 l1) :*: I (I0 l2))))))))) = l1 :||: l2+ to_ (Tag (R (R (R (R (R (L (C (I (I0 l)))))))))) = Not l+ to_ (Tag (R (R (R (R (R (R (L (C U))))))))) = T+ to_ (Tag (R (R (R (R (R (R (R (C U))))))))) = F++ index = Logic
multirec.cabal view
@@ -1,5 +1,5 @@ name: multirec-version: 0.1+version: 0.2 license: BSD3 license-file: LICENSE author: Alexey Rodriguez,@@ -21,7 +21,7 @@ . With the multirec library, we provide a mechanism to talk about fixed points of systems of datatypes that may be mutually recursive. On top- of this representations, generic functions such as the fold or the zipper+ of this representations, generic functions such as the fold or the Zipper can then be defined. . We expect that the library will be especially interesting for compiler@@ -38,20 +38,35 @@ stability: experimental build-type: Simple cabal-version: >= 1.2.1-tested-with: GHC == 6.8.3+tested-with: GHC == 6.8.3, GHC == 6.10.1 hs-source-dirs: src exposed-modules: Generics.MultiRec -- Base Generics.MultiRec.Base+ Generics.MultiRec.Constructor+ Generics.MultiRec.TH -- Generic functions+ Generics.MultiRec.ConNames Generics.MultiRec.HFunctor+ Generics.MultiRec.HFix Generics.MultiRec.Fold+ Generics.MultiRec.FoldK+ Generics.MultiRec.FoldAlg+ Generics.MultiRec.FoldAlgK Generics.MultiRec.Compos Generics.MultiRec.Eq+ Generics.MultiRec.Show extra-source-files: examples/AST.hs+ examples/ASTUse.hs+ examples/ASTTHUse.hs examples/ASTExamples.hs+ examples/Single.hs+ examples/SingleUse.hs+ examples/SingleTHUse.hs+ examples/SingleExamples.hs CREDITS-build-depends: base >= 3.0 +build-depends: base >= 3.0 && < 4,+ template-haskell >= 2.2 && < 2.4
src/Generics/MultiRec/Base.hs view
@@ -9,7 +9,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Generics.MultiRec.Base--- Copyright : (c) 2008 Universiteit Utrecht+-- Copyright : (c) 2008--2009 Universiteit Utrecht -- License : BSD3 -- -- Maintainer : generics@haskell.org@@ -29,9 +29,13 @@ module Generics.MultiRec.Base (-- * Structure types I(..), unI,- K(..), (:+:)(..), (:*:)(..),+ K(..), U(..), (:+:)(..), (:*:)(..), (:>:)(..), unTag,+ C(..), unC, + -- ** Constructor information+ module Generics.MultiRec.Constructor,+ -- ** Unlifted variants I0(..), K0(..), @@ -40,6 +44,7 @@ ) where import Control.Applicative+import Generics.MultiRec.Constructor -- * Structure types @@ -59,6 +64,9 @@ -- | Represents constant types that do not belong to the system. data K a (s :: * -> *) (r :: * -> *) ix = K {unK :: a} +-- | Represents constructors without fields.+data U (s :: * -> *) (r :: * -> *) ix = U+ -- | Represents sums (choices between constructors). data (f :+: g) (s :: * -> *) (r :: * -> *) ix = L (f s r ix) | R (g s r ix) @@ -74,6 +82,14 @@ unTag :: (f :>: ix) s r ix -> f s r ix unTag (Tag x) = x +-- | Represents constructors.+data C c f (s :: * -> *) (r :: * -> *) ix where+ C :: (Constructor c) => f s r ix -> C c f s r ix++-- | Destructor for 'C'.+unC :: C c f s r ix -> f s r ix+unC (C x) = x+ -- ** Unlifted variants -- | Unlifted version of 'I'.@@ -88,6 +104,9 @@ instance Applicative I0 where pure = I0 (I0 f) <*> (I0 x) = I0 (f x)++instance Functor (K0 a) where+ fmap f = K0 . unK0 -- * Indexed systems
src/Generics/MultiRec/Compos.hs view
@@ -4,7 +4,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Generics.MultiRec.Compos--- Copyright : (c) 2008 Universiteit Utrecht+-- Copyright : (c) 2008--2009 Universiteit Utrecht -- License : BSD3 -- -- Maintainer : generics@haskell.org@@ -18,6 +18,7 @@ -- ICFP 2006 -- -----------------------------------------------------------------------------+ module Generics.MultiRec.Compos where import Control.Monad (liftM)
+ src/Generics/MultiRec/ConNames.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE PatternSignatures #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.ConNames+-- Copyright : (c) 2008--2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- Generic function that returns the constructor names available in a system+-- of datatypes.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.ConNames where++import Generics.MultiRec.Base+import Generics.MultiRec.Constructor++class ConNames (f :: (* -> *) -> (* -> *) -> * -> *) where+ hconNames :: f s r ix -> [String]++instance Constructor c => ConNames (C c f) where+ hconNames c = [conName c]++instance (ConNames f, ConNames g) => ConNames (f :+: g) where+ hconNames (_ :: (f :+: g) r s ix) = hconNames (undefined :: f r s ix) +++ hconNames (undefined :: g r s ix)++instance ConNames (K x) where+ hconNames _ = []++instance ConNames U where+ hconNames _ = []++instance ConNames (f :*: g) where+ hconNames _ = []++instance ConNames (I a) where+ hconNames _ = []++instance (ConNames f) => ConNames (f :>: ix) where+ hconNames (_ :: (f :>: ix) r s xi) = hconNames (undefined :: f r s ix)++conNames :: forall s ix . (Ix s ix, ConNames (PF s)) => s ix -> [String]+conNames s = hconNames (undefined :: PF s s I0 ix)
+ src/Generics/MultiRec/Constructor.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE KindSignatures #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.Constructor+-- Copyright : (c) 2008--2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- This module contains a class for datatypes that represent data+-- constructors.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.Constructor+ (Constructor(..), Fixity(..), Associativity(..)+ ) where++-- | Class for datatypes that represent data constructors.+-- For non-symbolic constructors, only 'conName' has to be defined.+-- The weird argument is supposed to be instantiated with 'C' from+-- base, hence the complex kind.+class Constructor c where+ conName :: t c (f :: (* -> *) -> (* -> *) -> * -> *) (s :: * -> *) (r :: * -> *) ix -> String+ conFixity :: t c (f :: (* -> *) -> (* -> *) -> * -> *) (s :: * -> *) (r :: * -> *) ix -> Fixity+ conFixity = const Prefix++-- | Datatype to represent the fixity of a constructor. An infix declaration+-- directly corresponds to an application of 'Infix'.+data Fixity = Prefix | Infix Associativity Int+ deriving (Eq, Show, Ord, Read)++data Associativity = LeftAssociative | RightAssociative | NotAssociative+ deriving (Eq, Show, Ord, Read)+
src/Generics/MultiRec/Eq.hs view
@@ -1,12 +1,11 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Generics.MultiRec.Eq--- Copyright : (c) 2008 Universiteit Utrecht+-- Copyright : (c) 2008--2009 Universiteit Utrecht -- License : BSD3 -- -- Maintainer : generics@haskell.org@@ -16,6 +15,7 @@ -- Generic equality. -- -----------------------------------------------------------------------------+ module Generics.MultiRec.Eq where import Generics.MultiRec.Base@@ -30,9 +30,14 @@ instance HEq (I xi) where heq _ eq (I x1) (I x2) = eq index x1 x2 +-- | For constant types, we make use of the standard+-- equality function. instance Eq x => HEq (K x) where heq _ eq (K x1) (K x2) = x1 == x2 +instance HEq U where+ heq _ eq U U = True+ instance (HEq f, HEq g) => HEq (f :+: g) where heq ix eq (L x1) (L x2) = heq ix eq x1 x2 heq ix eq (R y1) (R y2) = heq ix eq y1 y2@@ -44,6 +49,9 @@ -- The following instance does not compile with ghc-6.8.2 instance HEq f => HEq (f :>: ix) where heq ix eq (Tag x1) (Tag x2) = heq ix eq x1 x2++instance HEq f => HEq (C c f) where+ heq ix eq (C x1) (C x2) = heq ix eq x1 x2 eq :: (Ix s ix, HEq (PF s)) => s ix -> ix -> ix -> Bool eq ix x1 x2 = heq ix (\ ix (I0 x1) (I0 x2) -> eq ix x1 x2) (from x1) (from x2)
src/Generics/MultiRec/Fold.hs view
@@ -4,19 +4,29 @@ {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LiberalTypeSynonyms #-} {-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Generics.MultiRec.Fold--- Copyright : (c) 2008 Universiteit Utrecht+-- Copyright : (c) 2008--2009 Universiteit Utrecht -- License : BSD3 -- -- Maintainer : generics@haskell.org -- Stability : experimental -- Portability : non-portable ----- The definition of generic fold.+-- The definition of generic fold, unfold, paramorphisms. In addition,+-- some combinators that facilitate the construction of algebras. --+-- There are several variants of fold in other modules that are probably+-- easier to use:+--+-- * for folds with constant return type, look at +-- "Generics.MultiRec.FoldAlgK" (or "Generics.MultiRec.FoldK"),+--+-- * for other folds, look at "Generics.MultiRec.FoldAlg".+-- ----------------------------------------------------------------------------- module Generics.MultiRec.Fold where@@ -24,26 +34,53 @@ import Generics.MultiRec.Base import Generics.MultiRec.HFunctor +import Control.Monad hiding (foldM)+import Control.Applicative+ -- * Generic fold and unfold -type Algebra s r = forall ix. Ix s ix => s ix -> PF s s r ix -> r ix+type Algebra' s f r = forall ix. Ix s ix => s ix -> f s r ix -> r ix+type Algebra s r = Algebra' s (PF s) r+type AlgebraF' s f g r = forall ix. Ix s ix => s ix -> f s r ix -> g (r ix)+type AlgebraF s g r = AlgebraF' s (PF s) g r fold :: (Ix s ix, HFunctor (PF s)) => Algebra s r -> ix -> r ix fold f = f index . hmap (\ _ (I0 x) -> fold f x) . from -type CoAlgebra s r = forall ix. Ix s ix => s ix -> r ix -> PF s s r ix+foldM :: (Ix s ix, HFunctor (PF s), Monad m) =>+ AlgebraF s m r -> ix -> m (r ix)+foldM f x = hmapM (\ _ (I0 x) -> foldM f x) (from x) >>= f index +type CoAlgebra' s f r = forall ix. Ix s ix => s ix -> r ix -> f s r ix+type CoAlgebra s r = CoAlgebra' s (PF s) r+type CoAlgebraF' s f g r = forall ix. Ix s ix => s ix -> r ix -> g (f s r ix)+type CoAlgebraF s g r = CoAlgebraF' s (PF s) g r+ unfold :: (Ix s ix, HFunctor (PF s)) => CoAlgebra s r -> r ix -> ix unfold f = to . hmap (\ _ x -> I0 (unfold f x)) . f index -type ParaAlgebra s r = forall ix. Ix s ix => s ix -> PF s s r ix -> ix -> r ix+unfoldM :: (Ix s ix, HFunctor (PF s), Monad m) =>+ CoAlgebraF s m r -> r ix -> m ix+unfoldM f x = f index x >>= liftMto . hmapM (\ _ x -> liftM I0 (unfoldM f x))+ where+ -- only for ghc-6.8.3 compatibility+ liftMto :: (Monad m, Ix s ix, pfs ~ PF s) => m (pfs s I0 ix) -> m ix+ liftMto = liftM to +type ParaAlgebra' s f r = forall ix. Ix s ix => s ix -> f s r ix -> ix -> r ix+type ParaAlgebra s r = ParaAlgebra' s (PF s) r+type ParaAlgebraF' s f g r = forall ix. Ix s ix => s ix -> f s r ix -> ix -> g (r ix)+type ParaAlgebraF s g r = ParaAlgebraF' s (PF s) g r+ para :: (Ix s ix, HFunctor (PF s)) => ParaAlgebra s r -> ix -> r ix para f x = f index (hmap (\ _ (I0 x) -> para f x) (from x)) x +paraM :: (Ix s ix, HFunctor (PF s), Monad m) => + ParaAlgebraF s m r -> ix -> m (r ix)+paraM f x = hmapM (\ _ (I0 x) -> paraM f x) (from x) >>= \ r -> f index r x -- * Creating an algebra @@ -59,4 +96,7 @@ tag :: AlgPart a s r ix -> AlgPart (a :>: ix) s r ix' tag f (Tag x) = f x++con :: AlgPart a s r ix -> AlgPart (C c a) s r ix+con f (C x) = f x
+ src/Generics/MultiRec/FoldAlg.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE LiberalTypeSynonyms #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.FoldAlg+-- Copyright : (c) 2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- A variant of fold that allows the specification of the algebra in a+-- convenient way.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.FoldAlg where++import Generics.MultiRec.Base+import Generics.MultiRec.HFunctor++-- * The type family of convenient algebras.++-- | The type family we use to describe the convenient algebras.+type family Alg (f :: (* -> *) -> (* -> *) -> * -> *) + (s :: * -> *) -- system+ (r :: * -> *) -- recursive positions+ (ix :: *) -- index+ :: *++-- | For a constant, we take the constant value to a result.+type instance Alg (K a) (s :: * -> *) (r :: * -> *) ix = a -> r ix++-- | For a unit, no arguments are available.+type instance Alg U (s :: * -> *) (r :: * -> *) ix = r ix++-- | For an identity, we turn the recursive result into a final result.+-- Note that the index can change.+type instance Alg (I xi) (s :: * -> *) r ix = r xi -> r ix++-- | For a sum, the algebra is a pair of two algebras.+type instance Alg (f :+: g) s r ix = (Alg f s r ix, Alg g s r ix)++-- | For a product where the left hand side is a constant, we+-- take the value as an additional argument.+type instance Alg (K a :*: g) s r ix = a -> Alg g s r ix++-- | For a product where the left hand side is an identity, we+-- take the recursive result as an additional argument.+type instance Alg (I xi :*: g) s r ix = r xi -> Alg g s r ix++-- | A tag changes the index of the final result.+type instance Alg (f :>: xi) s r ix = Alg f s r xi++-- | Constructors are ignored.+type instance Alg (C c f) s r ix = Alg f s r ix++-- | The algebras passed to the fold have to work for all index types+-- in the system. The additional witness argument is required only+-- to make GHC's typechecker happy.+type Algebra s r = forall ix. Ix s ix => s ix -> Alg (PF s) s r ix++-- * The class to turn convenient algebras into standard algebras.++-- | The class fold explains how to convert a convenient algebra+-- 'Alg' back into a function from functor to result, as required+-- by the standard fold function.+class Fold (f :: (* -> *) -> (* -> *) -> * -> *) where+ alg :: (Ix s ix) => Alg f s r ix -> f s r ix -> r ix++instance Fold (K a) where+ alg f (K x) = f x++instance Fold U where+ alg f U = f++instance Fold (I xi) where+ alg f (I x) = f x++instance (Fold f, Fold g) => Fold (f :+: g) where+ alg (f, g) (L x) = alg f x+ alg (f, g) (R x) = alg g x++instance (Fold g) => Fold (K a :*: g) where+ alg f (K x :*: y) = alg (f x) y++instance (Fold g) => Fold (I xi :*: g) where+ alg f (I x :*: y) = alg (f x) y++instance (Fold f) => Fold (f :>: xi) where+ alg f (Tag x) = alg f x++instance (Fold f) => Fold (C c f) where+ alg f (C x) = alg f x++-- * Interface++-- | Variant of fold that takes an additional witness argument.+fold_ :: forall s ix r . (Ix s ix, HFunctor (PF s), Fold (PF s)) =>+ s ix ->+ Algebra s r ->+ ix -> r ix+fold_ ix f = (alg :: Alg (PF s) s r ix -> (PF s) s r ix -> r ix) (f ix) .+ hmap (\ _ (I0 x) -> fold_ index f x) .+ from++-- | Fold with convenient algebras.+fold :: forall s ix r . (Ix s ix, HFunctor (PF s), Fold (PF s)) =>+ Algebra s r ->+ ix -> r ix+fold = fold_ index++-- * Construction of algebras++infixr 5 &++-- | For constructing algebras that are made of nested pairs rather+-- than n-ary tuples, it is helpful to use this pairing combinator.+(&) :: a -> b -> (a, b)+(&) = (,)
+ src/Generics/MultiRec/FoldAlgK.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE LiberalTypeSynonyms #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.FoldAlgK+-- Copyright : (c) 2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- A variant of fold that allows the specification of the algebra in a+-- convenient way, and that fixes the result type to a constant.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.FoldAlgK where++import Generics.MultiRec.Base+import Generics.MultiRec.HFunctor++-- * The type family of convenient algebras.++-- | The type family we use to describe the convenient algebras.+type family Alg (f :: (* -> *) -> (* -> *) -> * -> *) + (s :: * -> *) -- system+ (r :: *) -- result type+ :: *++-- | For a constant, we take the constant value to a result.+type instance Alg (K a) (s :: * -> *) r = a -> r++-- | For a unit, no arguments are available.+type instance Alg U (s :: * -> *) r = r++-- | For an identity, we turn the recursive result into a final result.+-- Note that the index can change.+type instance Alg (I xi) (s :: * -> *) r = r -> r++-- | For a sum, the algebra is a pair of two algebras.+type instance Alg (f :+: g) s r = (Alg f s r, Alg g s r)++-- | For a product where the left hand side is a constant, we+-- take the value as an additional argument.+type instance Alg (K a :*: g) s r = a -> Alg g s r++-- | For a product where the left hand side is an identity, we+-- take the recursive result as an additional argument.+type instance Alg (I xi :*: g) s r = r -> Alg g s r++-- | A tag changes the index of the final result.+type instance Alg (f :>: xi) s r = Alg f s r++-- | Constructors are ignored.+type instance Alg (C c f) s r = Alg f s r++-- | The algebras passed to the fold have to work for all index types+-- in the system. The additional witness argument is required only+-- to make GHC's typechecker happy.+type Algebra s r = forall ix. Ix s ix => s ix -> Alg (PF s) s r++-- * The class to turn convenient algebras into standard algebras.++-- | The class fold explains how to convert a convenient algebra+-- 'Alg' back into a function from functor to result, as required+-- by the standard fold function.+class Fold (f :: (* -> *) -> (* -> *) -> * -> *) where+ alg :: (Ix s ix) => Alg f s r -> f s (K0 r) ix -> r++instance Fold (K a) where+ alg f (K x) = f x++instance Fold U where+ alg f U = f++instance Fold (I xi) where+ alg f (I (K0 x)) = f x++instance (Fold f, Fold g) => Fold (f :+: g) where+ alg (f, g) (L x) = alg f x+ alg (f, g) (R x) = alg g x++instance (Fold g) => Fold (K a :*: g) where+ alg f (K x :*: y) = alg (f x) y++instance (Fold g) => Fold (I xi :*: g) where+ alg f (I (K0 x) :*: y) = alg (f x) y++instance (Fold f) => Fold (f :>: xi) where+ alg f (Tag x) = alg f x++instance (Fold f) => Fold (C c f) where+ alg f (C x) = alg f x++-- * Interface++-- | Variant of fold that takes an additional witness argument.+fold_ :: forall s ix r . (Ix s ix, HFunctor (PF s), Fold (PF s)) =>+ s ix ->+ Algebra s r ->+ ix -> r+fold_ ix f = (alg :: Alg (PF s) s r -> (PF s) s (K0 r) ix -> r) (f ix) .+ hmap (\ _ (I0 x) -> K0 (fold_ index f x)) .+ from++-- | Fold with convenient algebras.+fold :: forall s ix r . (Ix s ix, HFunctor (PF s), Fold (PF s)) =>+ Algebra s r ->+ ix -> r+fold = fold_ index++-- * Construction of algebras++infixr 5 &++-- | For constructing algebras that are made of nested pairs rather+-- than n-ary tuples, it is helpful to use this pairing combinator.+(&) :: a -> b -> (a, b)+(&) = (,)
+ src/Generics/MultiRec/FoldK.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LiberalTypeSynonyms #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeFamilies #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.FoldK+-- Copyright : (c) 2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- Variant of "Generics.MultiRec.Fold" where the result type is independent of+-- the index.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.FoldK where++import Generics.MultiRec.Base+import Generics.MultiRec.HFunctor++import Control.Monad hiding (foldM)+import Control.Applicative++-- * Generic fold and unfold++type Algebra' s f r = forall ix. Ix s ix => s ix -> f s (K0 r) ix -> r+type Algebra s r = Algebra' s (PF s) r+type AlgebraF' s f g r = forall ix. Ix s ix => s ix -> f s (K0 r) ix -> g r+type AlgebraF s g r = AlgebraF' s (PF s) g r++fold :: (Ix s ix, HFunctor (PF s)) =>+ Algebra s r -> ix -> r+fold f = f index . hmap (\ _ (I0 x) -> K0 (fold f x)) . from++foldM :: (Ix s ix, HFunctor (PF s), Monad m) =>+ AlgebraF s m r -> ix -> m r+foldM f x = hmapM (\ _ (I0 x) -> liftM K0 (foldM f x)) (from x) >>= f index++type CoAlgebra' s f r = forall ix. Ix s ix => s ix -> r -> f s (K0 r) ix+type CoAlgebra s r = CoAlgebra' s (PF s) r+type CoAlgebraF' s f g r = forall ix. Ix s ix => s ix -> r -> g (f s (K0 r) ix)+type CoAlgebraF s g r = CoAlgebraF' s (PF s) g r++unfold :: (Ix s ix, HFunctor (PF s)) =>+ CoAlgebra s r -> r -> ix+unfold f = to . hmap (\ _ (K0 x) -> I0 (unfold f x)) . f index++unfoldM :: (Ix s ix, HFunctor (PF s), Monad m) =>+ CoAlgebraF s m r -> r -> m ix+unfoldM f x = f index x >>= liftMto . hmapM (\ _ (K0 x) -> liftM I0 (unfoldM f x))+ where+ -- only for ghc-6.8.3 compatibility+ liftMto :: (Monad m, Ix s ix, pfs ~ PF s) => m (pfs s I0 ix) -> m ix+ liftMto = liftM to++type ParaAlgebra' s f r = forall ix. Ix s ix => s ix -> f s (K0 r) ix -> ix -> r+type ParaAlgebra s r = ParaAlgebra' s (PF s) r+type ParaAlgebraF' s f g r = forall ix. Ix s ix => s ix -> f s (K0 r) ix -> ix -> g r+type ParaAlgebraF s g r = ParaAlgebraF' s (PF s) g r++para :: (Ix s ix, HFunctor (PF s)) => + ParaAlgebra s r -> ix -> r+para f x = f index (hmap (\ _ (I0 x) -> K0 (para f x)) (from x)) x++paraM :: (Ix s ix, HFunctor (PF s), Monad m) => + ParaAlgebraF s m r -> ix -> m r+paraM f x = hmapM (\ _ (I0 x) -> liftM K0 (paraM f x)) (from x) >>= \ r -> f index r x++-- * Creating an algebra++infixr 5 &+infixr :->++type AlgPart a (s :: * -> *) b ix = a s (K0 b) ix -> b+type (f :-> g) (s :: * -> *) b ix = f s b ix -> g s b ix++(&) :: (AlgPart a :-> AlgPart b :-> AlgPart (a :+: b)) s c ix+(f & g) (L x) = f x+(f & g) (R x) = g x ++tag :: AlgPart a s c ix -> AlgPart (a :>: ix) s c ix'+tag f (Tag x) = f x++con :: AlgPart a s b ix -> AlgPart (C c a) s b ix+con f (C x) = f x
+ src/Generics/MultiRec/HFix.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.HFix+-- Copyright : (c) 2008--2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- Higher-order fixed point operator as well as conversion functions.+-- It is rarely necessary to use 'HFix'. Generic functions+-- usually convert between the original datatype and the functor directly.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.HFix where++import Generics.MultiRec.Base+import Generics.MultiRec.HFunctor++-- * Fixed point of indexed types++data HFix (h :: (* -> *) -> * -> *) ix = HIn { hout :: h (HFix h) ix }++hfrom :: (pfs ~ PF s, Ix s ix, HFunctor (PF s)) => ix -> HFix (pfs s) ix+hfrom = HIn . hmap (const (hfrom . unI0)) . from++hto :: (pfs ~ PF s, Ix s ix, HFunctor (PF s)) => HFix (pfs s) ix -> ix+hto = to . hmap (const (I0 . hto)) . hout
src/Generics/MultiRec/HFunctor.hs view
@@ -5,7 +5,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Generics.MultiRec.HFunctor--- Copyright : (c) 2008 Universiteit Utrecht+-- Copyright : (c) 2008--2009 Universiteit Utrecht -- License : BSD3 -- -- Maintainer : generics@haskell.org@@ -38,6 +38,9 @@ instance HFunctor (K x) where hmapA _ (K x) = pure (K x) +instance HFunctor U where+ hmapA _ U = pure U+ instance (HFunctor f, HFunctor g) => HFunctor (f :+: g) where hmapA f (L x) = liftA L (hmapA f x) hmapA f (R y) = liftA R (hmapA f y)@@ -47,6 +50,9 @@ instance HFunctor f => HFunctor (f :>: ix) where hmapA f (Tag x) = liftA Tag (hmapA f x)++instance HFunctor f => HFunctor (C c f) where+ hmapA f (C x) = liftA C (hmapA f x) -- | The function 'hmap' takes a functor @f@. All the recursive instances -- in that functor are wrapped by an application of @r@. The argument to
+ src/Generics/MultiRec/Show.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.Show+-- Copyright : (c) 2008--2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- Generic show.+--+-----------------------------------------------------------------------------++module Generics.MultiRec.Show where++import Generics.MultiRec.Base+import Generics.MultiRec.HFunctor+import Generics.MultiRec.Fold++import qualified Prelude as P+import Prelude hiding (show, showsPrec)++-- * Generic show++class HFunctor f => HShow f where+ hShowsPrecAlg :: Algebra' s f (K0 [Int -> ShowS])++instance HShow (I xi) where+ hShowsPrecAlg _ (I (K0 x)) = K0 x++-- | For constant types, we make use of the standard+-- show function.+instance Show x => HShow (K x) where+ hShowsPrecAlg _ (K x) = K0 [\ n -> P.showsPrec n x]++instance HShow U where+ hShowsPrecAlg _ U = K0 []++instance (HShow f, HShow g) => HShow (f :+: g) where+ hShowsPrecAlg ix (L x) = hShowsPrecAlg ix x+ hShowsPrecAlg ix (R y) = hShowsPrecAlg ix y++instance (HShow f, HShow g) => HShow (f :*: g) where+ hShowsPrecAlg ix (x :*: y) = K0 (unK0 (hShowsPrecAlg ix x) ++ unK0 (hShowsPrecAlg ix y))++instance HShow f => HShow (f :>: ix) where+ hShowsPrecAlg ix (Tag x) = hShowsPrecAlg ix x++instance HShow f => HShow (C c f) where+ hShowsPrecAlg ix cx@(C x) =+ case conFixity cx of+ Prefix -> K0 [\ n -> showParen (not (null fields) && n > 10)+ (spaces ((conName cx ++) : map ($ 11) fields))]+ Infix a p -> K0 [\ n -> showParen (n > p)+ (spaces (head fields p : (conName cx ++) : map ($ p) (tail fields)))]+ where+ fields = unK0 $ hShowsPrecAlg ix x++-- | A variant of the algebra that takes an extra argument+-- to fix the system 's' the algebra works on.+hShowsPrecAlg_ :: (HShow f) => s ix -> Algebra' s f (K0 [Int -> ShowS])+hShowsPrecAlg_ _ = hShowsPrecAlg ++showsPrec :: forall s ix. (Ix s ix, HShow (PF s)) => s ix -> Int -> ix -> ShowS+showsPrec ix n x = spaces (map ($ n) (unK0 (fold (hShowsPrecAlg_ ix) x)))++show :: forall s ix. (Ix s ix, HShow (PF s)) => s ix -> ix -> String+show ix x = showsPrec ix 0 x ""++-- * Utilities++spaces :: [ShowS] -> ShowS+spaces [] = id+spaces [x] = x+spaces (x:xs) = x . (' ':) . spaces xs
+ src/Generics/MultiRec/TH.hs view
@@ -0,0 +1,239 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}++-----------------------------------------------------------------------------+-- |+-- Module : Generics.MultiRec.TH+-- Copyright : (c) 2008--2009 Universiteit Utrecht+-- License : BSD3+--+-- Maintainer : generics@haskell.org+-- Stability : experimental+-- Portability : non-portable+--+-- This module contains Template Haskell code that can be used to+-- automatically generate the boilerplate code for the multiplate+-- library. The constructor information can be generated per datatype,+-- the rest per system of datatypes.+--+-----------------------------------------------------------------------------+++module Generics.MultiRec.TH+ ( deriveConstructors,+ deriveSystem,+ derivePF,+ deriveIx+ ) where++import Generics.MultiRec.Base+import Generics.MultiRec.Constructor+import Language.Haskell.TH hiding (Fixity())+import Language.Haskell.TH.Syntax (Lift(..))+import Control.Monad++-- | Given a list of datatype names, derive datatypes and +-- instances of class 'Constructor'.++deriveConstructors :: [Name] -> Q [Dec]+deriveConstructors =+ liftM concat . mapM constrInstance++-- | Given the name of the index GADT, the names of the+-- types in the system, and the name (as string) for the+-- pattern functor to derive, generate the 'Ix' and 'PF'+-- instances. /IMPORTANT/: It is assumed that the constructors+-- of the GADT have the same names as the datatypes in the+-- family.++deriveSystem :: Name -> [Name] -> String -> Q [Dec]+deriveSystem n ns pfn =+ do+ pf <- derivePF pfn ns+ ix <- deriveIx n ns+ return $ pf ++ ix++-- | Derive only the 'PF' instance. Not needed if 'deriveSystem'+-- is used.++derivePF :: String -> [Name] -> Q [Dec]+derivePF pfn ns =+ fmap (:[]) $+ tySynD (mkName pfn) [] (foldr1 sum (map (pfType ns) ns))+ where+ sum :: Q Type -> Q Type -> Q Type+ sum a b = conT ''(:+:) `appT` a `appT` b++-- | Derive only the 'Ix' instances. Not needed if 'deriveSystem'+-- is used.++deriveIx :: Name -> [Name] -> Q [Dec]+deriveIx s ns =+ zipWithM (ixInstance s ns (length ns)) [0..] ns++constrInstance :: Name -> Q [Dec]+constrInstance n =+ do+ i <- reify n+ -- runIO (print i)+ let cs = case i of+ TyConI (DataD _ _ _ cs _) -> cs+ _ -> []+ ds <- mapM mkData cs+ is <- mapM mkInstance cs+ return $ ds ++ is++mkData :: Con -> Q Dec+mkData (NormalC n _) =+ dataD (cxt []) (mkName (nameBase n)) [] [] [] +mkData (InfixC t1 n t2) =+ mkData (NormalC n [t1,t2])++instance Lift Fixity where+ lift Prefix = conE 'Prefix+ lift (Infix a n) = conE 'Infix `appE` [| a |] `appE` [| n |]++instance Lift Associativity where+ lift LeftAssociative = conE 'LeftAssociative+ lift RightAssociative = conE 'RightAssociative+ lift NotAssociative = conE 'NotAssociative++mkInstance :: Con -> Q Dec+mkInstance (NormalC n _) =+ instanceD (cxt []) (appT (conT ''Constructor) (conT $ mkName (nameBase n)))+ [funD 'conName [clause [wildP] (normalB (stringE (nameBase n))) []]]+mkInstance (InfixC t1 n t2) =+ do+ i <- reify n+ let fi = case i of+ DataConI _ _ _ f -> convertFixity f+ _ -> Prefix+ instanceD (cxt []) (appT (conT ''Constructor) (conT $ mkName (nameBase n)))+ [funD 'conName [clause [wildP] (normalB (stringE (nameBase n))) []],+ funD 'conFixity [clause [wildP] (normalB [| fi |]) []]]+ where+ convertFixity (Fixity n d) = Infix (convertDirection d) n+ convertDirection InfixL = LeftAssociative+ convertDirection InfixR = RightAssociative+ convertDirection InfixN = NotAssociative++pfType :: [Name] -> Name -> Q Type+pfType ns n =+ do+ -- runIO $ putStrLn $ "processing " ++ show n+ i <- reify n+ let b = case i of+ TyConI (DataD _ _ _ cs _) ->+ foldr1 sum (map (pfCon ns) cs)+ TyConI (TySynD t _ _) ->+ conT ''K `appT` conT t+ _ -> error "unknown construct" + appT (appT (conT ''(:>:)) b) (conT $ mkName (nameBase n))+ where+ sum :: Q Type -> Q Type -> Q Type+ sum a b = conT ''(:+:) `appT` a `appT` b++pfCon :: [Name] -> Con -> Q Type+pfCon ns (NormalC n []) =+ appT (appT (conT ''C) (conT $ mkName (nameBase n))) (conT ''U)+pfCon ns (NormalC n fs) =+ appT (appT (conT ''C) (conT $ mkName (nameBase n))) (foldr1 prod (map (pfField ns . snd) fs))+ where+ prod :: Q Type -> Q Type -> Q Type+ prod a b = conT ''(:*:) `appT` a `appT` b+pfCon ns (InfixC t1 n t2) =+ pfCon ns (NormalC n [t1,t2])++pfField :: [Name] -> Type -> Q Type+pfField ns t@(ConT n) | n `elem` ns = conT ''I `appT` return t+pfField ns t = conT ''K `appT` return t++ixInstance :: Name -> [Name] -> Int -> Int -> Name -> Q Dec+ixInstance s ns m i n =+ instanceD (cxt []) (conT ''Ix `appT` conT s `appT` conT n)+ [mkFrom ns n m i, mkTo ns n m i, mkIndex n]++mkFrom :: [Name] -> Name -> Int -> Int -> Q Dec+mkFrom ns n m i =+ do+ -- runIO $ putStrLn $ "processing " ++ show n+ let wrapE e = lrE m i (conE 'Tag `appE` e)+ i <- reify n+ let b = case i of+ TyConI (DataD _ _ _ cs _) ->+ zipWith (fromCon wrapE ns (length cs)) [0..] cs+ TyConI (TySynD t _ _) ->+ [clause [varP (field 0)] (normalB (wrapE $ conE 'K `appE` varE (field 0))) []]+ _ -> error "unknown construct" + funD 'from_ b ++mkTo :: [Name] -> Name -> Int -> Int -> Q Dec+mkTo ns n m i =+ do+ -- runIO $ putStrLn $ "processing " ++ show n+ let wrapP p = lrP m i (conP 'Tag [p])+ i <- reify n+ let b = case i of+ TyConI (DataD _ _ _ cs _) ->+ zipWith (toCon wrapP ns (length cs)) [0..] cs+ TyConI (TySynD t _ _) ->+ [clause [wrapP $ conP 'K [varP (field 0)]] (normalB $ varE (field 0)) []]+ _ -> error "unknown construct" + funD 'to_ b ++mkIndex :: Name -> Q Dec+mkIndex n =+ funD 'index [clause [] (normalB (conE (mkName (nameBase n)))) []]++fromCon :: (Q Exp -> Q Exp) -> [Name] -> Int -> Int -> Con -> Q Clause+fromCon wrap ns m i (NormalC n []) =+ clause+ [conP n []]+ (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []+fromCon wrap ns m i (NormalC n fs) =+ -- runIO (putStrLn ("constructor " ++ show ix)) >>+ clause+ [conP n (map (varP . field) [0..length fs - 1])]+ (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField ns) [0..] (map snd fs))) []+ where+ prod x y = conE '(:*:) `appE` x `appE` y+fromCon wrap ns m i (InfixC t1 n t2) =+ fromCon wrap ns m i (NormalC n [t1,t2])++toCon :: (Q Pat -> Q Pat) -> [Name] -> Int -> Int -> Con -> Q Clause+toCon wrap ns m i (NormalC n []) =+ clause+ [wrap $ lrP m i $ conP 'C [conP 'U []]]+ (normalB $ conE n) []+toCon wrap ns m i (NormalC n fs) =+ -- runIO (putStrLn ("constructor " ++ show ix)) >>+ clause+ [wrap $ lrP m i $ conP 'C [foldr1 prod (zipWith (toField ns) [0..] (map snd fs))]]+ (normalB $ foldl appE (conE n) (map (varE . field) [0..length fs - 1])) []+ where+ prod x y = conP '(:*:) [x,y]+toCon wrap ns m i (InfixC t1 n t2) =+ toCon wrap ns m i (NormalC n [t1,t2])++fromField :: [Name] -> Int -> Type -> Q Exp+fromField ns nr t@(ConT n) | n `elem` ns = conE 'I `appE` (conE 'I0 `appE` varE (field nr))+fromField ns nr t = conE 'K `appE` varE (field nr)++toField :: [Name] -> Int -> Type -> Q Pat+toField ns nr t@(ConT n) | n `elem` ns = conP 'I [conP 'I0 [varP (field nr)]]+toField ns nr t = conP 'K [varP (field nr)]++field :: Int -> Name+field n = mkName $ "f" ++ show n++lrP :: Int -> Int -> (Q Pat -> Q Pat)+lrP 1 0 p = p+lrP m 0 p = conP 'L [p]+lrP m i p = conP 'R [lrP (m-1) (i-1) p]++lrE :: Int -> Int -> (Q Exp -> Q Exp)+lrE 1 0 e = e+lrE m 0 e = conE 'L `appE` e+lrE m i e = conE 'R `appE` lrE (m-1) (i-1) e+