generics-mrsop-2.0.0: src/Generics/MRSOP/AG.hs
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
-- | Attribute grammars over mutual recursive datatypes
module Generics.MRSOP.AG where
import Generics.MRSOP.Base
-- | Annotated version of Fix. This is basically the 'Cofree' datatype,
-- but for n-ary functors
data AnnFix (ki :: kon -> *) (codes :: [[[Atom kon]]]) (phi :: Nat -> *) (n :: Nat) =
AnnFix (phi n)
(Rep ki (AnnFix ki codes phi) (Lkup n codes))
getAnn :: AnnFix ki codes ann ix -> ann ix
getAnn (AnnFix a _) = a
annCata :: IsNat ix
=> (forall iy. IsNat iy => chi iy -> Rep ki phi (Lkup iy codes) -> phi iy)
-> AnnFix ki codes chi ix
-> phi ix
annCata f (AnnFix a x) = f a (mapRep (annCata f) x)
-- | Forget the annotations
forgetAnn :: AnnFix ki codes a ix -> Fix ki codes ix
forgetAnn (AnnFix _ rep) = Fix (mapRep forgetAnn rep)
mapAnn :: (IsNat ix)
=> (forall iy. chi iy -> phi iy)
-> AnnFix ki codes chi ix
-> AnnFix ki codes phi ix
mapAnn f = synthesizeAnn (\x _ -> f x)
-- | Synthesized attributes
synthesizeAnn :: forall ki codes chi phi ix
. (IsNat ix)
=>
(forall iy. chi iy -> Rep ki phi (Lkup iy codes) -> phi iy)
-> AnnFix ki codes chi ix
-> AnnFix ki codes phi ix
synthesizeAnn f = annCata alg
where
alg :: forall iy
. chi iy
-> Rep ki (AnnFix ki codes phi) (Lkup iy codes)
-> AnnFix ki codes phi iy
alg ann rep = AnnFix (f ann (mapRep getAnn rep)) rep
-- |Example of using 'synthesize' to annotate a tree with its size
-- at every node.
--
-- > sizeAlgebra :: Rep ki (Const (Sum Int)) xs -> Const (Sum Int) iy
-- > sizeAlgebra = (Const 1 <>) . monoidAlgebra
--
-- Annotate each node with the number of subtrees
--
-- > sizeGeneric' :: (IsNat ix)
-- > => Fix ki codes ix -> AnnFix ki codes (Const (Sum Int)) ix
-- > sizeGeneric' = synthesize sizeAlgebra
--
-- Note how using just 'cata' will simply count the number of nodes
--
-- > sizeGeneric :: (IsNat ix)
-- > => Fix ki codes ix -> Const (Sum Int) ix
-- > sizeGeneric = cata sizeAlgebra
--
synthesize :: forall ki phi codes ix
. (IsNat ix)
=> (forall iy . (IsNat iy) => Rep ki phi (Lkup iy codes) -> phi iy)
-> Fix ki codes ix
-> AnnFix ki codes phi ix
synthesize f = cata alg
where
alg :: forall iy
. (IsNat iy)
=> Rep ki (AnnFix ki codes phi) (Lkup iy codes)
-> AnnFix ki codes phi iy
alg xs = AnnFix (f (mapRep getAnn xs)) xs