grammar-combinators-0.1: Text/GrammarCombinators/Base/Domain.hs
{- Copyright 2010 Dominique Devriese
This file is part of the grammar-combinators library.
The grammar-combinators library is free software: you can
redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at
your option) any later version.
Foobar is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with Foobar. If not, see
<http://www.gnu.org/licenses/>.
-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Text.GrammarCombinators.Base.Domain (
DomainMap(supIx, subIx),
DomainEmbedding(supPF),
SubVal(MkSubVal, unSubVal),
IxMapId, IxMapBase, IxMapSeq, ApplyIxMap,
MemoFam(toMemo, fromMemo), Memo, memoFamily,
FoldFam(foldFam),
EqFam(overrideIdx, eqIdx), overrideIdxK,
ShowFam(showIdx),
Domain,
memoFamilyK, toMemoK, fromMemoK,
LiftFam(liftIdxE, liftIdxP)
) where
import Generics.MultiRec.Base
import Generics.MultiRec.HFunctor
import Language.Haskell.TH.Syntax (Exp, Pat)
data IxMapId
data IxMapBase (m :: * -> *)
data IxMapSeq (l1 :: *) (l2 :: * -> *)
type family ApplyIxMap (m :: *) ix
type instance ApplyIxMap (IxMapBase m) ix = m ix
type instance ApplyIxMap (IxMapSeq l1 l2) ix = ApplyIxMap l1 (l2 ix)
type instance ApplyIxMap IxMapId ix = ix
class MemoFam (phi :: * -> *) where
data Memo phi :: (* -> *) -> *
fromMemo :: Memo phi v -> (forall ix. phi ix -> v ix)
toMemo :: (forall ix. phi ix -> v ix) -> Memo phi v
memoFamily :: (MemoFam phi) =>
(forall ix. phi ix -> v ix) -> (forall ix. phi ix -> v ix)
memoFamily f = fromMemo (toMemo f)
memoFamilyK :: (MemoFam phi) =>
(forall ix. phi ix -> v) -> (forall ix. phi ix -> v)
memoFamilyK f = fromMemoK (toMemoK f)
toMemoK :: (MemoFam phi) =>
(forall ix. phi ix -> v) -> Memo phi (K0 v)
toMemoK f = toMemo (K0 . f)
fromMemoK :: (MemoFam phi) =>
Memo phi (K0 v) -> phi ix -> v
fromMemoK m = unK0 . fromMemo m
-- | A domain 'phi' that is an instance of the 'FoldFam' type class supports
-- folding over all non-terminals in the domain using the 'foldFam' function.
class FoldFam phi where
-- | Fold a given function over all non-terminals in the domain 'phi'.
foldFam :: (forall ix. phi ix -> b -> b) -> b -> b
-- | A domain 'phi' that is an instance of the 'ShowFam' type class supports
-- conversion of non-terminal proof terms to Strings using the 'showIdx' function.
class ShowFam phi where
-- | Convert a given non-terminal proof term to a String representation.
showIdx :: forall ix. phi ix -> String
-- | A domain 'phi' that is an instance of the 'EqFam' type class supports
-- overriding a function over the full domain at a single non-terminal using
-- the |overrideIdx| function.
class EqFam phi where
-- | Test equality of two given non-terminal proof terms.
eqIdx :: forall ix1 ix2. phi ix1 -> phi ix2 -> Bool
eqIdx idx1 = overrideIdxK (const False) idx1 True
-- | Override a function over the full domain at a single non-terminal.
overrideIdx :: (forall ix'. phi ix' -> r ix') -> phi oix ->
r oix -> phi ix -> r ix
-- | Similar to the 'overrideIdx' function, but limited to functions whose result type is
-- the same for all non-terminals.
overrideIdxK :: (EqFam phi) => (forall ix'. phi ix' -> v) -> phi oix -> v -> phi ix -> v
overrideIdxK f idx v = unK0 . overrideIdx (K0 . f) idx (K0 v)
-- | A decent Domain 'phi' should instantiate the 'FoldFam', 'ShowFam', 'EqFam' and 'MemoFam'. Avoid
-- using this type class in constraints, use more specific type classes whenever possible.
--
-- Note: instances for this type class are not automatically derived, and you have to manually instantiate
-- it with an empty implementation block.
class (FoldFam phi,
ShowFam phi,
EqFam phi,
MemoFam phi) => Domain phi
class DomainMap phi phi' supIxT where
supIx :: phi' ix -> phi (supIxT ix)
subIx :: phi (supIxT ix) -> phi' ix
class (DomainMap phi phi' supIxT) =>
DomainEmbedding phi phi' supIxT where
supPF :: (HFunctor phi (PF phi)) =>
phi' ix -> phi (supIxT ix) ->
PF phi' (SubVal supIxT r) ix -> PF phi r (supIxT ix)
-- | A generic wrapper type that restricts a semantic value family over a bigger domain
-- to a smaller domain.
data SubVal (supIxT :: * -> *) v ix = MkSubVal {
unSubVal :: v (supIxT ix)
} deriving (Show)
class LiftFam phi where
liftIdxE :: phi ix -> Exp
liftIdxP :: phi ix -> Pat