bound-2.0.6: examples/Overkill.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wincomplete-patterns -Wno-orphans #-}
module Main where
import Data.Kind
import qualified Data.Vector as Vector
import Data.Vector (Vector)
import qualified Data.List as List
import Data.Foldable
import Data.Traversable
import Control.Monad
import Control.Applicative
import Prelude hiding (foldr)
import Data.Functor.Classes
import Data.Type.Equality
import Bound
infixl 9 :@
infixr 5 :>
data Exp a
= Var a
| Exp a :@ Exp a
| forall (b :: Index). Lam (Pat b Exp a) (Scope (Path b) Exp a)
| Let (Vector (Scope Int Exp a)) (Scope Int Exp a)
data Index = VarI | WildI | AsI Index | ConI [Index]
data Pat :: Index -> (Type -> Type) -> Type -> Type where
VarP :: Pat 'VarI f a
WildP :: Pat 'WildI f a
AsP :: Pat i f a -> Pat ('AsI i) f a
ConP :: String -> Pats bs f a -> Pat ('ConI bs) f a
ViewP :: f a -> Pat b f a -> Pat b f a -- TODO: allow references to earlier variables
data Pats :: [Index] -> (Type -> Type) -> Type -> Type where
NilP :: Pats '[] f a
(:>) :: Pat b f a -> Pats bs f a -> Pats (b ': bs) f a
data Path :: Index -> Type where
V :: Path 'VarI
L :: Path ('AsI a)
R :: Path a -> Path ('AsI a)
C :: MPath as -> Path ('ConI as)
data MPath :: [Index] -> Type where
H :: Path a -> MPath (a ':as)
T :: MPath as -> MPath (a ':as)
instance Functor Exp where
fmap = fmapDefault
instance Foldable Exp where
foldMap = foldMapDefault
instance Applicative Exp where
pure = Var
(<*>) = ap
instance Traversable Exp where
traverse f (Var a) = Var <$> f a
traverse f (x :@ y) = (:@) <$> traverse f x <*> traverse f y
traverse f (Lam p e) = Lam <$> traverse f p <*> traverse f e
traverse f (Let bs e) = Let <$> traverse (traverse f) bs <*> traverse f e
instance Monad Exp where
#if !(MIN_VERSION_base(4,11,0))
return = Var
#endif
Var a >>= f = f a
(x :@ y) >>= f = (x >>= f) :@ (y >>= f)
Lam p e >>= f = Lam (p >>>= f) (e >>>= f)
Let bs e >>= f = Let (fmap (>>>= f) bs) (e >>>= f)
instance Eq a => Eq (Exp a) where (==) = eq1
instance Eq1 Exp where
liftEq eq (Var a) (Var b) = eq a b
liftEq eq (a :@ a') (b :@ b') = liftEq eq a b && liftEq eq a' b'
liftEq eq (Lam ps a) (Lam qs b) =
case eqPat' eq ps qs of
Nothing -> False
Just Refl -> liftEq eq a b
liftEq eq (Let as a) (Let bs b) = liftEq (liftEq eq) as bs && liftEq eq a b
liftEq _ _ _ = False
instance Show a => Show (Exp a) where showsPrec = showsPrec1
instance Show1 Exp where
liftShowsPrec s _ d (Var a) = showParen (d > 10) $ showString "Var " . s 11 a
liftShowsPrec s sl d (a :@ b) = showParen (d > 9) $ liftShowsPrec s sl 9 a . showString " :@ " . liftShowsPrec s sl 10 b
liftShowsPrec s sl d (Lam ps b) = showParen (d > 10) $ showString "Lam " . liftShowsPrec s sl 11 ps . showChar ' ' . liftShowsPrec s sl 11 b
liftShowsPrec s sl d (Let bs b) = showParen (d > 10) $ showString "Let " . liftShowsPrec (liftShowsPrec s sl) (liftShowList s sl) 11 bs . showChar ' ' . liftShowsPrec s sl 11 b
-- * smart lam
-- ** smart patterns
data P a = forall b. P (Pat b Exp a) [a] (a -> Maybe (Path b))
varp :: Eq a => a -> P a
varp a = P VarP [a] (\v -> if a == v then Just V else Nothing)
wildp :: P a
wildp = P WildP [] (const Nothing)
asp :: Eq a => a -> P a -> P a
asp a (P p as f) = P (AsP p) (a:as) $ \v -> case f v of
Just b -> Just (R b)
Nothing | a == v -> Just L
| otherwise -> Nothing
data Ps a = forall bs. Ps (Pats bs Exp a) [a] (a -> Maybe (MPath bs))
conp :: String -> [P a] -> P a
conp g ps = case go ps of
Ps qs as f -> P (ConP g qs) as (fmap C . f)
where
go :: [P a] -> Ps a
go [] = Ps NilP [] (const Nothing)
go (P p as f : xs) = case go xs of
Ps ps' ass g' -> Ps (p :> ps') (as ++ ass) $ \v ->
T <$> g' v <|> H <$> f v
-- * smart lam
lam :: P a -> Exp a -> Exp a
lam (P p _ f) t = Lam p (abstract f t)
-- * smart let
let_ :: Eq a => [(a, Exp a)] -> Exp a -> Exp a
let_ bs b = Let (Vector.fromList $ map (abstr . snd) bs) (abstr b)
where vs = map fst bs
abstr = abstract (`List.elemIndex` vs)
-- * Pat
-- ** A Kind of Shape
eqPat :: (Eq1 f) => (a -> b -> Bool) -> Pat i f a -> Pat i' f b -> Bool
eqPat _ VarP VarP = True
eqPat _ WildP WildP = True
eqPat eq (AsP p) (AsP q) = eqPat eq p q
eqPat eq (ConP g ps) (ConP h qs) = g == h && eqPats eq ps qs
eqPat eq (ViewP e p) (ViewP f q) = liftEq eq e f && eqPat eq p q
eqPat _ _ _ = False
-- The same as eqPat, but if the patterns are equal, it returns a
-- proof that their type arguments are the same.
eqPat' :: (Eq1 f) => (a -> a' -> Bool) -> Pat b f a -> Pat b' f a' -> Maybe (b :~: b')
eqPat' _ VarP VarP = Just Refl
eqPat' _ WildP WildP = Just Refl
eqPat' eq (AsP p) (AsP q) = do
Refl <- eqPat' eq p q
Just Refl
eqPat' eq (ConP g ps) (ConP h qs) = do
guard (g == h)
Refl <- eqPats' eq ps qs
Just Refl
eqPat' eq (ViewP e p) (ViewP f q) = guard (liftEq eq e f) >> eqPat' eq p q
eqPat' _ _ _ = Nothing
instance Eq1 f => Eq1 (Pat b f) where liftEq = eqPat
instance (Eq1 f, Eq a) => Eq (Pat b f a) where (==) = eq1
instance (Show1 f, Show a) => Show (Pat b f a) where showsPrec = showsPrec1
instance Show1 f => Show1 (Pat b f) where
liftShowsPrec _ _ _ VarP = showString "VarP"
liftShowsPrec _ _ _ WildP = showString "WildP"
liftShowsPrec s sl d (AsP p) = showParen (d > 10) $ showString "AsP " . liftShowsPrec s sl 11 p
liftShowsPrec s sl d (ConP g ps) = showParen (d > 10) $ showString "ConP " . showsPrec 11 g . showChar ' ' . liftShowsPrec s sl 11 ps
liftShowsPrec s sl d (ViewP e p) = showParen (d > 10) $ showString "ViewP " . liftShowsPrec s sl 11 e . showChar ' ' . liftShowsPrec s sl 11 p
instance Functor f => Functor (Pat b f) where
fmap _ VarP = VarP
fmap _ WildP = WildP
fmap f (AsP p) = AsP (fmap f p)
fmap f (ConP g ps) = ConP g (fmap f ps)
fmap f (ViewP e p) = ViewP (fmap f e) (fmap f p)
instance Foldable f => Foldable (Pat b f) where
foldMap f (AsP p) = foldMap f p
foldMap f (ConP _g ps) = foldMap f ps
foldMap f (ViewP e p) = foldMap f e `mappend` foldMap f p
foldMap _ _ = mempty
instance Traversable f => Traversable (Pat b f) where
traverse _ VarP = pure VarP
traverse _ WildP = pure WildP
traverse f (AsP p) = AsP <$> traverse f p
traverse f (ConP g ps) = ConP g <$> traverse f ps
traverse f (ViewP e p) = ViewP <$> traverse f e <*> traverse f p
instance Bound (Pat b) where
VarP >>>= _ = VarP
WildP >>>= _ = WildP
AsP p >>>= f = AsP (p >>>= f)
ConP g ps >>>= f = ConP g (ps >>>= f)
ViewP e p >>>= f = ViewP (e >>= f) (p >>>= f)
-- ** Pats
eqPats :: (Eq1 f) => (a -> b -> Bool) -> Pats bs f a -> Pats bs' f b -> Bool
eqPats _ NilP NilP = True
eqPats eq (p :> ps) (q :> qs) = eqPat eq p q && eqPats eq ps qs
eqPats _ _ _ = False
-- Like eqPats, but if the patses are equal, it returns a proof that their
-- type arguments are the same.
eqPats' :: (Eq1 f) => (a -> a' -> Bool) -> Pats bs f a -> Pats bs' f a' -> Maybe (bs :~: bs')
eqPats' _ NilP NilP = Just Refl
eqPats' eq (p :> ps) (q :> qs) = do
Refl <- eqPat' eq p q
Refl <- eqPats' eq ps qs
Just Refl
eqPats' _ _ _ = Nothing
instance Eq1 f => Eq1 (Pats bs f) where liftEq = eqPats
instance (Eq1 f, Eq a) => Eq (Pats bs f a) where (==) = eq1
instance (Show1 f, Show a) => Show (Pats bs f a) where showsPrec = showsPrec1
instance Show1 f => Show1 (Pats bs f) where
liftShowsPrec _ _ _ NilP = showString "NilP"
liftShowsPrec s sl d (p :> ps) = showParen (d > 5) $
liftShowsPrec s sl 6 p . showString " :> " . liftShowsPrec s sl 5 ps
instance Functor f => Functor (Pats bs f) where
fmap _ NilP = NilP
fmap f (p :> ps) = fmap f p :> fmap f ps
instance Foldable f => Foldable (Pats bs f) where
foldMap f (p :> ps) = foldMap f p `mappend` foldMap f ps
foldMap _ _ = mempty
instance Traversable f => Traversable (Pats bs f) where
traverse _f NilP = pure NilP
traverse f (p :> ps) = (:>) <$> traverse f p <*> traverse f ps
instance Bound (Pats bs) where
NilP >>>= _ = NilP
(p :> ps) >>>= f = (p >>>= f) :> (ps >>>= f)
-- ** Path into Pats
-- Internally, this is only used to implement eqPath, which is only
-- used to implement this.
eqMPath :: MPath is -> MPath js -> Bool
eqMPath (H m) (H n) = eqPath m n
eqMPath (T p) (T q) = eqMPath p q
eqMPath _ _ = False
instance Eq (MPath is) where
H m == H n = m == n
T p == T q = p == q
_ == _ = False
-- Internally, this is only used to define comparePath, which
-- is only used here to define this.
compareMPath :: MPath is -> MPath js -> Ordering
compareMPath (H m) (H n) = comparePath m n
compareMPath (H _) (T _) = LT
compareMPath (T p) (T q) = compareMPath p q
compareMPath (T _) (H _) = GT
instance Ord (MPath is) where
compare (H m) (H n) = compare m n
compare (H _) (T _) = LT
compare (T p) (T q) = compare p q
compare (T _) (H _) = GT
instance Show (MPath is) where
showsPrec d (H m) = showParen (d > 10) $ showString "H " . showsPrec 11 m
showsPrec d (T p) = showParen (d > 10) $ showString "T " . showsPrec 11 p
-- instance Read (MPath is)
-- ** Path into Pat
-- Internally, this is only used to implement eqMPath, which is only used
-- to implement this.
eqPath :: Path i -> Path j -> Bool
eqPath V V = True
eqPath L L = True
eqPath (R m) (R n) = eqPath m n
eqPath (C p) (C q) = eqMPath p q
eqPath _ _ = False
instance Eq (Path i) where
p == q = case compare p q of
EQ -> True
_ -> False
-- Internally, this is only used to define compareMPath, which
-- is only used here to define this.
comparePath :: Path i -> Path j -> Ordering
comparePath V V = EQ
comparePath V _ = LT
comparePath L V = GT
comparePath L L = EQ
comparePath L _ = LT
comparePath (R _) V = GT
comparePath (R _) L = GT
comparePath (R m) (R n) = comparePath m n
comparePath (R _) (C _) = LT
comparePath (C p) (C q) = compareMPath p q
comparePath (C _) _ = GT
instance Ord (Path i) where
compare V y = case (y :: Path 'VarI) of V -> EQ
compare L y = cpL y
where
cpL :: Path ('AsI a) -> Ordering
cpL L = EQ
cpL (R _) = LT
compare (R r) y = cpR r y
where
cpR :: Path a -> Path ('AsI a) -> Ordering
cpR _ L = GT
cpR m (R n) = compare m n
compare (C c) y = cpC c y
where
cpC :: MPath as -> Path ('ConI as) -> Ordering
cpC p (C q) = compare p q
instance Show (Path i) where
showsPrec _ V = showString "V"
showsPrec _ L = showString "L"
showsPrec d (R m) = showParen (d > 10) $ showString "R " . showsPrec 11 m
showsPrec d (C p) = showParen (d > 10) $ showString "C " . showsPrec 11 p
-- |
-- >>> let_ [("x",Var "y"),("y",Var "x" :@ Var "y")] $ lam (varp "z") (Var "z" :@ Var "y")
-- Let (fromList [Scope (Var (B 1)),Scope (Var (B 0) :@ Var (B 1))]) (Scope (Lam VarP (Scope (Var (B V) :@ Var (F (Var (B 1)))))))
--
-- >>> lam (varp "x") (Var "x")
-- Lam VarP (Scope (Var (B V)))
--
-- >>> lam (conp "Hello" [varp "x", wildp]) (Var "y")
-- Lam (ConP "Hello" (VarP :> WildP :> NilP)) (Scope (Var (F (Var "y"))))
main :: IO ()
main = return ()