{-# 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.-------------------------------------------------------------------------------moduleGenerics.MultiRec.FoldAlgwhereimportGenerics.MultiRec.BaseimportGenerics.MultiRec.HFunctor-- * The type family of convenient algebras.-- | The type family we use to describe the convenient algebras.typefamilyAlg(f::(*->*)->*->*)(r::*->*)-- recursive positions(ix::*)-- index::*-- | For a constant, we take the constant value to a result.typeinstanceAlg(Ka)(r::*->*)ix=a->rix-- | For a unit, no arguments are available.typeinstanceAlgU(r::*->*)ix=rix-- | For an identity, we turn the recursive result into a final result.-- Note that the index can change.typeinstanceAlg(Ixi)rix=rxi->rix-- | For a sum, the algebra is a pair of two algebras.typeinstanceAlg(f:+:g)rix=(Algfrix,Alggrix)-- | For a product where the left hand side is a constant, we-- take the value as an additional argument.typeinstanceAlg(Ka:*:g)rix=a->Alggrix-- | For a product where the left hand side is an identity, we-- take the recursive result as an additional argument.typeinstanceAlg(Ixi:*:g)rix=rxi->Alggrix-- | A tag changes the index of the final result.typeinstanceAlg(f:>:xi)rix=Algfrxi-- | Constructors are ignored.typeinstanceAlg(Ccf)rix=Algfrix-- | The algebras passed to the fold have to work for all index types-- in the family. The additional witness argument is required only-- to make GHC's typechecker happy.typeAlgebraphir=forallix.phiix->Alg(PFphi)rix-- * 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.classFold(f::(*->*)->*->*)wherealg::Algfrix->frix->rixinstanceFold(Ka)wherealgf(Kx)=fxinstanceFoldUwherealgfU=finstanceFold(Ixi)wherealgf(Ix)=fxinstance(Foldf,Foldg)=>Fold(f:+:g)wherealg(f,g)(Lx)=algfxalg(f,g)(Rx)=alggxinstance(Foldg)=>Fold(Ka:*:g)wherealgf(Kx:*:y)=alg(fx)yinstance(Foldg)=>Fold(Ixi:*:g)wherealgf(Ix:*:y)=alg(fx)yinstance(Foldf)=>Fold(f:>:xi)wherealgf(Tagx)=algfxinstance(Foldf)=>Fold(Ccf)wherealgf(Cx)=algfx-- * Interface-- | Fold with convenient algebras.fold::forallphiixr.(Famphi,HFunctorphi(PFphi),Fold(PFphi))=>Algebraphir->phiix->ix->rixfoldfp=alg(fp).hmap(\p(I0x)->foldfpx).fromp-- * Construction of algebrasinfixr5&-- | 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)(&)=(,)