bound-0.1: examples/Exp.hs
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE TypeOperators #-}
module Exp where
import Data.Vector as Vector hiding ((++), map)
import Data.List as List
import Data.Foldable
import Data.Traversable
import Data.Monoid (Monoid(..))
import Control.Monad
import Control.Monad.Trans.Class
import Control.Applicative
import Prelude hiding (foldr)
import Prelude.Extras
import GHC.Prim (Constraint(..))
import Unsafe.Coerce
import Bound
-- ghci> 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)))))))
--
-- ghc> lam (varp "x") (Var "x")
-- ghc> lam (conp "Hello" [varp "x", wildp])) (Var "y")
infixl 9 :@
infixr 5 :>
-- little orphan instances
instance Show1 Vector where showsPrec1 = showsPrec
instance Eq1 Vector where (==#) = (==)
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)
-- | Case (Exp a) [Alt Exp a]
data Alt f a = forall b. Alt (Pat b f a) (Scope (Path b) Exp a)
data Index = VarI | WildI | AsI Index | ConI [Index]
data Pat :: Index -> (* -> *) -> * -> * 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] -> (* -> *) -> * -> * where
NilP :: Pats '[] f a
(:>) :: Pat b f a -> Pats bs f a -> Pats (b ': bs) f a
data Path :: Index -> * where
V :: Path VarI
L :: Path (AsI a)
R :: Path a -> Path (AsI a)
C :: MPath as -> Path (ConI as)
data MPath :: [Index] -> * 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
return = Var
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)
-- Case e as >>= f = Case (e >>= f) (fmap (>>>= f) as)
instance Eq a => Eq (Exp a) where (==) = (==#)
instance Eq1 Exp where
Var a ==# Var b = a == b
(a :@ b) ==# (c :@ d) = a ==# c && b ==# d
Lam ps a ==# Lam qs b = eqPat ps qs && a ==# unsafeCoerce b -- eqPat proves equal shape
Let as a ==# Let bs b = as == bs && a ==# b
-- Case e as ==# Case f bs = e ==# f && as == bs
_ ==# _ = False
instance Show a => Show (Exp a) where showsPrec = showsPrec1
instance Show1 Exp where
showsPrec1 d (Var a) = showParen (d > 10) $ showString "Var " . showsPrec 11 a
showsPrec1 d (a :@ b) = showParen (d > 9) $ showsPrec1 9 a . showString " :@ " . showsPrec1 10 b
showsPrec1 d (Lam ps b) = showParen (d > 10) $ showString "Lam " . showsPrec1 11 ps . showChar ' ' . showsPrec1 11 b
showsPrec1 d (Let bs b) = showParen (d > 10) $ showString "Let " . showsPrec1 11 bs . showChar ' ' . showsPrec1 11 b
{-
instance Eq1 f => Eq1 (Alt f) where
Alt p s ==# Alt q t = eqPat p q && s == unsafeCoerce t
instance (Eq1 f, Eq a) => Eq (Alt f) where (==) = (==#)
instance Show1 f => Show1 (Alt f) where
showsPrec d (Alt p s) = showsPrec d (Alt p s)
-}
-- * 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, Eq a) => Pat b f a -> Pat b' f a -> Bool
eqPat VarP VarP = True
eqPat WildP WildP = True
eqPat (AsP p) (AsP q) = eqPat p q
eqPat (ConP g ps) (ConP h qs) = g == h && eqPats ps qs
eqPat (ViewP e p) (ViewP f q) = e ==# f && eqPat p q
instance Eq1 f => Eq1 (Pat b f) where (==#) = eqPat
instance (Eq1 f, Eq a) => Eq (Pat b f a) where (==) = eqPat
instance Show1 f => Show1 (Pat b f) where showsPrec1 = showsPrec
instance (Show1 f, Show a) => Show (Pat b f a) where
showsPrec _ VarP = showString "VarP"
showsPrec _ WildP = showString "WildP"
showsPrec d (AsP p) = showParen (d > 10) $ showString "AsP " . showsPrec 11 p
showsPrec d (ConP g ps) = showParen (d > 10) $ showString "ConP " . showsPrec 11 g . showChar ' ' . showsPrec 11 ps
showsPrec d (ViewP e p) = showParen (d > 10) $ showString "ViewP " . showsPrec1 11 e . showChar ' ' . showsPrec 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, Eq a) => Pats bs f a -> Pats bs' f a -> Bool
eqPats NilP NilP = True
eqPats (p :> ps) (q :> qs) = eqPat p q && eqPats ps qs
eqPats _ _ = False
instance Eq1 f => Eq1 (Pats bs f) where (==#) = eqPats
instance (Eq1 f, Eq a) => Eq (Pats bs f a) where (==) = eqPats
instance (Show1 f, Show a) => Show (Pats bs f a) where showsPrec = showsPrec1
instance Show1 f => Show1 (Pats bs f) where
showsPrec1 _ NilP = showString "NilP"
showsPrec1 d (p :> ps) = showParen (d > 5) $
showsPrec1 6 p . showString " :> " . showsPrec1 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
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 (==) = eqMPath
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 = compareMPath
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
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 (==) = eqPath
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 V = EQ
compare L L = EQ
compare L _ = LT
compare (R _) L = GT
compare (R m) (R n) = compare m n
compare (C 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