packages feed

binder 0.1 → 0.2

raw patch · 6 files changed

+604/−105 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Binder: class MkFree m a
- Data.Binder: instance GHC.Base.Applicative (Data.Binder.Closure m)
- Data.Binder: instance GHC.Base.Functor (Data.Binder.Box m)
- Data.Binder: instance GHC.Base.Functor (Data.Binder.Closure m)
- Data.Binder: mkFree :: MkFree m a => Var m a -> a
+ Data.Binder: bindApply :: MonadNumbering m => Box m (Binder a m b) -> Box m a -> m (Box m b)
+ Data.Binder: bindList :: MonadNumbering m => VarList m a -> Box m b -> Box m (BinderList a m b)
+ Data.Binder: bindListApply :: MonadNumbering m => Box m (BinderList a m b) -> Box m [a] -> m (Box m b)
+ Data.Binder: binder'mkFree :: forall a_a8Hl m_a8Hm b_a8Hn. Lens' (Binder a_a8Hl m_a8Hm b_a8Hn) (Var m_a8Hm a_a8Hl -> m_a8Hm a_a8Hl)
+ Data.Binder: binderList'Arity :: Getter (BinderList a m b) Int
+ Data.Binder: binderList'Body :: forall a_a9u5 m_a9u6 b_a9u7 b_a9Rc. Lens (BinderList a_a9u5 m_a9u6 b_a9u7) (BinderList a_a9u5 m_a9u6 b_a9Rc) ([a_a9u5] -> m_a9u6 b_a9u7) ([a_a9u5] -> m_a9u6 b_a9Rc)
+ Data.Binder: binderList'Names :: forall a_a9u5 m_a9u6 b_a9u7. Lens' (BinderList a_a9u5 m_a9u6 b_a9u7) [Text]
+ Data.Binder: binderList'mkFree :: forall a_a9u5 m_a9u6 b_a9u7. Lens' (BinderList a_a9u5 m_a9u6 b_a9u7) (Var m_a9u6 a_a9u5 -> m_a9u6 a_a9u5)
+ Data.Binder: boxBinderList :: MonadNumbering m => (b -> m (Box m b)) -> BinderList a m b -> m (Box m (BinderList a m b))
+ Data.Binder: boxJoin :: MonadNumbering m => Box m (m a) -> m (Box m a)
+ Data.Binder: boxList :: MonadNumbering m => [Box m a] -> Box m [a]
+ Data.Binder: boxVarList :: VarList m a -> [Box m a]
+ Data.Binder: data BinderList a m b
+ Data.Binder: eqBinderList :: MonadNumbering m => (b -> b -> m Bool) -> BinderList a m b -> BinderList a m b -> m Bool
+ Data.Binder: instance GHC.Base.Applicative m => GHC.Base.Applicative (Data.Binder.Closure m)
+ Data.Binder: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Binder.Box m)
+ Data.Binder: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Binder.Closure m)
+ Data.Binder: namesOf :: VarList m a -> [Text]
+ Data.Binder: newVarList :: MonadNumbering m => [Text] -> (Var m a -> m a) -> m (VarList m a)
+ Data.Binder: substList :: BinderList a m b -> [a] -> m b
+ Data.Binder: type VarList m a = [Var m a]
+ Data.Binder: unbindList :: MonadNumbering m => BinderList a m b -> m (VarList m a, b)
+ Data.Binder: var'mkFree :: Lens' (Var m a) (Var m a -> m a)
+ Data.Binder: varList'Boxes :: Getter (VarList m a) [Box m a]
+ Data.Binder: varList'Keys :: Getter (VarList m a) [Numbering m]
+ Data.Binder: varList'Names :: Getter (VarList m a) [Text]
- Data.Binder: bind :: (MkFree m a, MonadNumbering m) => Var m a -> Box m b -> Box m (Binder a b)
+ Data.Binder: bind :: MonadNumbering m => Var m a -> Box m b -> Box m (Binder a m b)
- Data.Binder: binder'Body :: forall a_a8FU b_a8FV a_a9mq b_a9mr. Lens (Binder a_a8FU b_a8FV) (Binder a_a9mq b_a9mr) (a_a8FU -> b_a8FV) (a_a9mq -> b_a9mr)
+ Data.Binder: binder'Body :: forall a_a8Hl m_a8Hm b_a8Hn b_a9ts. Lens (Binder a_a8Hl m_a8Hm b_a8Hn) (Binder a_a8Hl m_a8Hm b_a9ts) (a_a8Hl -> m_a8Hm b_a8Hn) (a_a8Hl -> m_a8Hm b_a9ts)
- Data.Binder: binder'Name :: forall a_a8FU b_a8FV. Lens' (Binder a_a8FU b_a8FV) Text
+ Data.Binder: binder'Name :: forall a_a8Hl m_a8Hm b_a8Hn. Lens' (Binder a_a8Hl m_a8Hm b_a8Hn) Text
- Data.Binder: boxApply :: (a -> b) -> Box m a -> Box m b
+ Data.Binder: boxApply :: Functor m => (a -> b) -> Box m a -> Box m b
- Data.Binder: boxBinder :: (MkFree m a, MonadNumbering m) => (b -> m (Box m b)) -> Binder a b -> m (Box m (Binder a b))
+ Data.Binder: boxBinder :: MonadNumbering m => (b -> m (Box m b)) -> Binder a m b -> m (Box m (Binder a m b))
- Data.Binder: buildBinder :: Var m a -> (a -> b) -> Binder a b
+ Data.Binder: buildBinder :: Var m a -> (a -> m b) -> Binder a m b
- Data.Binder: data Binder a b
+ Data.Binder: data Binder a m b
- Data.Binder: eqBinder :: (MkFree m a, MonadNumbering m) => (b -> b -> m Bool) -> Binder a b -> Binder a b -> m Bool
+ Data.Binder: eqBinder :: MonadNumbering m => (b -> b -> m Bool) -> Binder a m b -> Binder a m b -> m Bool
- Data.Binder: newVar :: forall m a. (MkFree m a, MonadNumbering m) => Text -> m (Var m a)
+ Data.Binder: newVar :: forall m a. MonadNumbering m => Text -> (Var m a -> m a) -> m (Var m a)
- Data.Binder: subst :: Binder a b -> a -> b
+ Data.Binder: subst :: Binder a m b -> a -> m b
- Data.Binder: unbind :: (MkFree m a, MonadNumbering m) => Binder a b -> m (Var m a, b)
+ Data.Binder: unbind :: MonadNumbering m => Binder a m b -> m (Var m a, b)
- Data.Binder: unbox :: forall m a. Box m a -> a
+ Data.Binder: unbox :: forall m a. Monad m => Box m a -> m a
- Data.Binder: var'Key :: forall m_a6Xp a_a6Xq. Lens' (Var m_a6Xp a_a6Xq) (Numbering m_a6Xp)
+ Data.Binder: var'Key :: forall m_a6Y1 a_a6Y2. Lens' (Var m_a6Y1 a_a6Y2) (Numbering m_a6Y1)

Files

CHANGELOG.md view
@@ -2,6 +2,13 @@  ## version 0 +### 0.2 -- 2023-10-06++* Add operations for list.+* Integrate mkFree function into Var and Binder.+* Now MkFree requires monadic instance.+* Binder requires Monad typeclass.+ ### 0.1 -- 2023-10-04  Initial release.
binder.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               binder-version:            0.1+version:            0.2 synopsis:           Variable binding for abstract syntax tree description:     binder is purely functional implementation of Ocaml's@@ -29,11 +29,12 @@ source-repository this     type:     git     location: https://github.com/ijaketak/binder-    tag:      0.1+    tag:      0.2  common depends     build-depends:           containers < 0.8+        , lens < 5.3         , text < 2.2         , transformers < 0.7 @@ -48,7 +49,6 @@     -- other-extensions:     build-depends:           base < 4.19-        , lens < 5.3     hs-source-dirs:   src     default-language: Haskell2010 @@ -58,6 +58,7 @@     other-modules:           Binder1Spec         , Binder2Spec+        , Binder3Spec     -- other-extensions:     type:             exitcode-stdio-1.0     hs-source-dirs:   test
src/Data/Binder.hs view
@@ -24,10 +24,10 @@ -- * Variable and Box   , Var   , Box-  , MkFree(..) -- ** Variable   , var'Key   , var'Name+  , var'mkFree   , var'Box   , nameOf   , boxVar@@ -45,9 +45,12 @@   , boxPair   , boxTriple   , boxT+  , boxList+  , boxJoin -- * Variable binding   , Binder   , binder'Name+  , binder'mkFree   , binder'Body   , subst   , buildBinder@@ -55,9 +58,32 @@   , unbind   , eqBinder   , boxBinder+  , bindApply+-- * List+-- * Variable list+  , VarList+  , varList'Keys+  , varList'Names+  , varList'Boxes+  , namesOf+  , boxVarList+  , newVarList+-- * Binder for list+  , BinderList+  , binderList'Names+  , binderList'Body+  , binderList'mkFree+  , binderList'Arity+  , substList+  , eqBinderList+  , bindList+  , unbindList+  , boxBinderList+  , bindListApply   ) where  import Control.Lens+import Control.Monad (join) import Data.Kind (Type) import qualified Data.Map.Lazy as M import Data.Maybe (fromJust)@@ -78,6 +104,7 @@   } data VarBody m a = VarBody   { _varBody'Name :: Text+  , _varBody'mkFree :: Var m a -> m a   , _varBody'Box :: Box m a   } -- | Representation of under-construction things@@ -86,23 +113,22 @@   = Box'Closed a   | Box'Env (EnvVar m) (Closure m a) --- | Typeclass for free variable constructor.-class MkFree m a where-  mkFree :: Var m a -> a--data AnyVar m = forall a. MkFree m a => AnyVar (Var m a)+data AnyVar m = forall a. AnyVar (Var m a) type EnvVar m = M.Map (Numbering m) (AnyVar m)-data AnyMkFree m = forall a. MkFree m a => AnyMkFree a-type EnvMkFree m = M.Map (Numbering m) (AnyMkFree m)-newtype Closure m a = Closure { unClosure :: (EnvMkFree m) -> a }+data AnyOne = forall a. AnyOne a+type EnvOne m = M.Map (Numbering m) AnyOne+newtype Closure m a = Closure { unClosure :: (EnvOne m) -> m a } -instance Functor (Closure m) where-  fmap f cla = Closure $ f . unClosure cla+instance Functor m => Functor (Closure m) where+  fmap f cla = Closure $ fmap f . unClosure cla -instance Applicative (Closure m) where-  pure a = Closure $ const a-  clf <*> cla = Closure $ \env -> unClosure clf env $ unClosure cla env+instance Applicative m => Applicative (Closure m) where+  pure a = Closure $ const $ pure a+  clf <*> cla = Closure $ \env -> unClosure clf env <*> unClosure cla env +closureJoin :: Monad m => Closure m (m a) -> Closure m a+closureJoin cl = Closure $ \env -> join $ unClosure cl env+ instance MonadNumbering m => Eq (Var m a) where   Var x _ == Var y _ = x == y @@ -115,6 +141,8 @@  var'Name :: Lens' (Var m a) Text var'Name = var'Body . varBody'Name+var'mkFree :: Lens' (Var m a) (Var m a -> m a)+var'mkFree = var'Body . varBody'mkFree var'Box :: Lens' (Var m a) (Box m a) var'Box = var'Body . varBody'Box @@ -134,15 +162,15 @@ boxVar x = x ^. var'Box  -- | Create a new variable with given name.-newVar :: forall m a. (MkFree m a, MonadNumbering m) => Text -> m (Var m a)-newVar name = do+newVar :: forall m a. MonadNumbering m => Text -> (Var m a -> m a) -> m (Var m a)+newVar name mkFree = do   i <- numbering   let x = let b = Box'Env                 (M.singleton i $ AnyVar x)                 (Closure $ \env ->-                  let f (AnyMkFree y) = unsafeCoerce y+                  let f (AnyOne y) = pure $ unsafeCoerce y                    in f $ fromJust $ M.lookup i env)-           in Var i $ VarBody name b+           in Var i $ VarBody name mkFree b   return x  @@ -157,31 +185,31 @@ occur v (Box'Env vs _) = M.member (v ^. var'Key) vs  -instance Functor (Box m) where+instance Functor m => Functor (Box m) where   fmap f (Box'Closed a) = Box'Closed (f a)   fmap f (Box'Env vs ta) = Box'Env vs (f <$> ta) -instance (MonadNumbering m) => Applicative (Box m) where+instance MonadNumbering m => Applicative (Box m) where   pure = Box'Closed   Box'Closed f <*> Box'Closed a = Box'Closed (f a)   Box'Closed f <*> Box'Env va ta = Box'Env va (f <$> ta)   Box'Env vf tf <*> Box'Closed a = Box'Env vf (appClosure tf a)    where-    appClosure clf x = Closure $ \env -> unClosure clf env x+    appClosure clf x = Closure $ \env -> unClosure clf env <*> pure x   Box'Env vf tf <*> Box'Env va ta = Box'Env (M.union vf va) (tf <*> ta)  -- | Pick out and complete the construction of @a@.-unbox :: forall m a. Box m a -> a-unbox (Box'Closed t) = t-unbox (Box'Env env cl) = unClosure cl $ f <$> env+unbox :: forall m a. Monad m => Box m a -> m a+unbox (Box'Closed t) = pure t+unbox (Box'Env env cl) = unClosure cl =<< traverse f env  where-  f (AnyVar x) = AnyMkFree @m $ mkFree x+  f (AnyVar x) = fmap AnyOne $ x ^. var'mkFree $ x  box :: MonadNumbering m => a -> Box m a box = pure apBox :: MonadNumbering m => Box m (a -> b) -> Box m a -> Box m b apBox = (<*>)-boxApply :: (a -> b) -> Box m a -> Box m b+boxApply :: Functor m => (a -> b) -> Box m a -> Box m b boxApply = fmap boxApply2 :: MonadNumbering m => (a -> b -> c) -> Box m a -> Box m b -> Box m c boxApply2 f ta tb = f <$> ta <*> tb@@ -195,61 +223,183 @@ boxTriple = boxApply3 (,,) boxT :: (MonadNumbering m, Traversable t) => t (Box m a) -> Box m (t a) boxT = sequenceA+boxList :: MonadNumbering m => [Box m a] -> Box m [a]+boxList = sequenceA+boxJoin :: MonadNumbering m => Box m (m a) -> m (Box m a)+boxJoin (Box'Closed ma) = return . Box'Closed =<< ma+boxJoin (Box'Env env cl) = return $ Box'Env env $ closureJoin cl   -- | Variable binding.---   Essentially, @Binder a b@ means @a -> b@.-data Binder a b = Binder+--   Essentially, @Binder a m b@ means @a -> m b@.+data Binder a m b = Binder   { _binder'Name :: Text-  , _binder'Body :: a -> b+  , _binder'mkFree :: Var m a -> m a+  , _binder'Body :: a -> m b   }  $(makeLenses ''Binder)  -- | Variable substitution.-subst :: Binder a b -> a -> b+subst :: Binder a m b -> a -> m b subst b = b ^. binder'Body  -- | unbinding-unbind :: (MkFree m a, MonadNumbering m) => Binder a b -> m (Var m a, b)+unbind :: MonadNumbering m => Binder a m b -> m (Var m a, b) unbind b = do-  x <- newVar $ b ^. binder'Name-  return (x, subst b $ mkFree x)+  let mkFree = b ^. binder'mkFree+  x <- newVar (b ^. binder'Name) mkFree+  y <- subst b =<< mkFree x+  return (x, y) -unbind2 :: (MkFree m a, MonadNumbering m)-        => Binder a b1 -> Binder a b2 -> m (Var m a, b1, b2)+unbind2 :: MonadNumbering m+        => Binder a m b1 -> Binder a m b2 -> m (Var m a, b1, b2) unbind2 b1 b2 = do-  x <- newVar $ b1 ^. binder'Name-  let v = mkFree x-  return (x, subst b1 v, subst b2 v)+  let mkFree = b1 ^. binder'mkFree+  x <- newVar (b1 ^. binder'Name) mkFree+  v <- mkFree x+  y1 <- subst b1 v+  y2 <- subst b2 v+  return (x, y1, y2)  -- | Check if two bindings are equal.-eqBinder :: (MkFree m a, MonadNumbering m)-         => (b -> b -> m Bool) -> Binder a b -> Binder a b -> m Bool+eqBinder :: MonadNumbering m+         => (b -> b -> m Bool) -> Binder a m b -> Binder a m b -> m Bool eqBinder eq f g = do   (_, t, u) <- unbind2 f g   eq t u   -- | Smart constructor for 'Binder'.-buildBinder :: Var m a -> (a -> b) -> Binder a b-buildBinder x body = Binder (x ^. var'Name) body+buildBinder :: Var m a -> (a -> m b) -> Binder a m b+buildBinder x body = Binder (x ^. var'Name) (x ^. var'mkFree) body  -- | binding-bind :: (MkFree m a, MonadNumbering m)-        => Var m a -> Box m b -> Box m (Binder a b)-bind x (Box'Closed t) = Box'Closed $ buildBinder x $ const t+bind :: MonadNumbering m => Var m a -> Box m b -> Box m (Binder a m b)+bind x (Box'Closed t) = Box'Closed $ buildBinder x $ const $ return t bind x (Box'Env vs t) =   let vs' = M.delete (x ^. var'Key) vs in if length vs' == 0     then Box'Closed $ buildBinder x $-      \arg -> unClosure t $ M.singleton (x ^. var'Key) (AnyMkFree arg)+      \arg -> unClosure t $ M.singleton (x ^. var'Key) (AnyOne arg)     else Box'Env vs' $ Closure $-      \ms -> buildBinder x $-      \arg -> unClosure t $ M.insert (x ^. var'Key) (AnyMkFree arg) ms+      \ms -> return $ buildBinder x $+      \arg -> unClosure t $ M.insert (x ^. var'Key) (AnyOne arg) ms -boxBinder :: (MkFree m a, MonadNumbering m)-          => (b -> m (Box m b)) -> Binder a b -> m (Box m (Binder a b))+boxBinder :: MonadNumbering m+          => (b -> m (Box m b)) -> Binder a m b -> m (Box m (Binder a m b)) boxBinder f b = do   (x, t) <- unbind b   ft <- f t   return $ bind x ft++bindApply :: MonadNumbering m => Box m (Binder a m b) -> Box m a -> m (Box m b)+bindApply b arg = boxJoin $ subst <$> b <*> arg+++type VarList m a = [Var m a]++varList'Keys :: Getter (VarList m a) [Numbering m]+varList'Keys = to $ fmap $ view var'Key+varList'Names :: Getter (VarList m a) [Text]+varList'Names = to $ fmap $ view var'Name+varList'Boxes :: Getter (VarList m a) [Box m a]+varList'Boxes = to $ fmap $ view var'Box++-- | The names of variables.+namesOf :: VarList m a -> [Text]+namesOf = fmap $ view var'Name++-- | Smart constructor for a list of 'Box'.+boxVarList :: VarList m a -> [Box m a]+boxVarList = fmap $ view var'Box++-- | Create new variables with given names.+newVarList :: MonadNumbering m => [Text] -> (Var m a -> m a) -> m (VarList m a)+newVarList names mkFree = sequence $ flip fmap names $ \name -> newVar name mkFree+++-- | Essentially, @BinderList a m b@ means @[a] -> m b@.+data BinderList a m b = BinderList+  { _binderList'Names :: [Text]+  , _binderList'mkFree :: Var m a -> m a+  , _binderList'Body :: [a] -> m b+  }++$(makeLenses ''BinderList)++binderList'Arity :: Getter (BinderList a m b) Int+binderList'Arity = binderList'Names . to length++-- | Variable substitution.+substList :: BinderList a m b -> [a] -> m b+substList ba = ba ^. binderList'Body++-- | unbinding+unbindList :: MonadNumbering m => BinderList a m b -> m (VarList m a, b)+unbindList ba = do+  let mkFree = ba ^. binderList'mkFree+  xs <- newVarList (ba ^. binderList'Names) mkFree+  y <- substList ba =<< traverse mkFree xs+  return (xs, y)++unbind2List :: MonadNumbering m+             => BinderList a m b1 -> BinderList a m b2+             -> m (VarList m a, b1, b2)+unbind2List ba1 ba2 = do+  let mkFree = ba1 ^. binderList'mkFree+  xs <- newVarList (ba1 ^. binderList'Names) mkFree+  vs <- traverse mkFree xs+  y1 <- substList ba1 vs+  y2 <- substList ba2 vs+  return (xs, y1, y2)++-- | Check if two bindings are equal.+eqBinderList :: MonadNumbering m+              => (b -> b -> m Bool)+              -> BinderList a m b -> BinderList a m b -> m Bool+eqBinderList eq f g =+  if f ^. binderList'Arity /= g ^. binderList'Arity+    then return False+    else do+      (_, t, u) <- unbind2List f g+      eq t u++-- | Smart constructor for 'BinderList.+buildBinderList :: VarList m a -> ([a] -> m b) -> BinderList a m b+buildBinderList xs body =+  BinderList (xs ^. varList'Names) (head xs ^. var'mkFree) body++deleteList :: Ord k => [k] -> M.Map k a -> M.Map k a+deleteList = flip $ foldl $ \m k -> M.delete k m+insertList :: Ord k => [k] -> [a] -> M.Map k a -> M.Map k a+insertList ks xs m = foldl f m $ zip ks xs+ where+  f n (k, x) = M.insert k x n+zipList :: Ord k => [k] -> [a] -> M.Map k a+zipList ks xs = insertList ks xs M.empty++-- | binding+bindList :: MonadNumbering m+          => VarList m a -> Box m b -> Box m (BinderList a m b)+bindList xs (Box'Closed t) = Box'Closed $ buildBinderList xs $ const $ return t+bindList xs (Box'Env vs t) =+  let vs' = deleteList (xs ^. varList'Keys) vs in if length vs' == 0+    then Box'Closed $ buildBinderList xs $+      \args -> unClosure t $+      zipList (xs ^. varList'Keys) (AnyOne <$> args)+    else Box'Env vs' $ Closure $+      \ms -> return $ buildBinderList xs $+      \args -> unClosure t $+      insertList (xs ^. varList'Keys) (AnyOne <$> args) ms++boxBinderList :: MonadNumbering m+               => (b -> m (Box m b)) -> BinderList a m b+               -> m (Box m (BinderList a m b))+boxBinderList f b = do+  (xs, t) <- unbindList b+  ft <- f t+  return $ bindList xs ft++bindListApply :: MonadNumbering m+              => Box m (BinderList a m b) -> Box m [a] -> m (Box m b)+bindListApply b args = boxJoin $ substList <$> b <*> args
test/Binder1Spec.hs view
@@ -37,15 +37,15 @@  data Term   = Term'Var (Var S Term)-  | Term'Abs (Binder Term Term)+  | Term'Abs (Binder Term S Term)   | Term'App Term Term -instance MkFree S Term where-  mkFree = Term'Var+term'mkFree :: Var S Term -> S Term+term'mkFree = return . Term'Var  var :: Var S Term -> Box S Term var = boxVar-absRaw :: Box S (Binder Term Term) -> Box S Term+absRaw :: Box S (Binder Term S Term) -> Box S Term absRaw = fmap Term'Abs abs :: Var S Term -> Box S Term -> Box S Term abs x t = absRaw $ bind x t@@ -56,11 +56,13 @@ boxTerm (Term'Abs b) = absRaw <$> boxBinder boxTerm b boxTerm (Term'App t u) = app <$> boxTerm t <*> boxTerm u -eval :: Term -> Term-eval t@(Term'App f a) = case eval f of-  Term'Abs b -> eval (subst b a)-  _ -> t-eval t = t+eval :: Term -> S Term+eval t@(Term'App f a) = do+  ef <- eval f+  case ef of+    Term'Abs b -> eval =<< subst b a+    _ -> return t+eval t = return t  size :: Term -> S Int size (Term'Var _) = return 0@@ -86,18 +88,18 @@  termIdentity, termFst, termDelta, termOmega :: S Term termIdentity = do-  x <- newVar "x"-  return $ unbox $ abs x $ var x+  x <- newVar "x" term'mkFree+  unbox $ abs x $ var x termFst = do-  x <- newVar "x"-  y <- newVar "y"-  return $ unbox $ abs x $ abs y $ var x+  x <- newVar "x" term'mkFree+  y <- newVar "y" term'mkFree+  unbox $ abs x $ abs y $ var x termDelta = do-  x <- newVar "x"-  return $ unbox $ abs x $ app (var x) (var x)+  x <- newVar "x" term'mkFree+  unbox $ abs x $ app (var x) (var x) termOmega = do   delta <- box <$> termDelta-  return $ unbox $ app delta delta+  unbox $ app delta delta  spec :: Spec spec = do
test/Binder2Spec.hs view
@@ -39,38 +39,38 @@ data Ty   = Ty'Var (Var S Ty)   | Ty'Arr Ty Ty-  | Ty'All (Binder Ty Ty)+  | Ty'All (Binder Ty S Ty)  data Te   = Te'Var (Var S Te)-  | Te'Abs Ty (Binder Te Te)+  | Te'Abs Ty (Binder Te S Te)   | Te'App Te Te-  | Te'Lam (Binder Ty Te)+  | Te'Lam (Binder Ty S Te)   | Te'Spe Te Ty -instance MkFree S Ty where-  mkFree = Ty'Var-instance MkFree S Te where-  mkFree = Te'Var+ty'mkFree :: Var S Ty -> S Ty+ty'mkFree = return . Ty'Var+te'mkFree :: Var S Te -> S Te+te'mkFree = return . Te'Var  ty'Var :: Var S Ty -> Box S Ty ty'Var = boxVar ty'Arr :: Box S Ty -> Box S Ty -> Box S Ty ty'Arr a b = Ty'Arr <$> a <*> b-ty'AllRaw :: Box S (Binder Ty Ty) -> Box S Ty+ty'AllRaw :: Box S (Binder Ty S Ty) -> Box S Ty ty'AllRaw = fmap Ty'All ty'All :: Var S Ty -> Box S Ty -> Box S Ty ty'All x t = ty'AllRaw $ bind x t  te'Var :: Var S Te -> Box S Te te'Var = boxVar-te'AbsRaw :: Box S Ty -> Box S (Binder Te Te) -> Box S Te+te'AbsRaw :: Box S Ty -> Box S (Binder Te S Te) -> Box S Te te'AbsRaw a f = Te'Abs <$> a <*> f te'Abs :: Box S Ty -> Var S Te -> Box S Te -> Box S Te te'Abs a x t = te'AbsRaw a $ bind x t te'App :: Box S Te -> Box S Te -> Box S Te te'App t u = Te'App <$> t <*> u-te'LamRaw :: Box S (Binder Ty Te) -> Box S Te+te'LamRaw :: Box S (Binder Ty S Te) -> Box S Te te'LamRaw = fmap Te'Lam te'Lam :: Var S Ty -> Box S Te -> Box S Te te'Lam x t = te'LamRaw $ bind x t@@ -88,36 +88,41 @@ boxTe (Te'Lam f) = te'LamRaw <$> boxBinder boxTe f boxTe (Te'Spe t a) = te'Spe <$> boxTe t <*> boxTy a -hnf :: Te -> Te-hnf (Te'App t u) = let v = hnf u in case hnf t of-  Te'Abs _ b -> hnf $ subst b v-  h -> Te'App h v-hnf (Te'Spe t a) = case hnf t of-  Te'Lam b -> hnf $ subst b a-  h -> Te'Spe h a-hnf t = t+hnf :: Te -> S Te+hnf (Te'App t u) = do+  hu <- hnf u+  ht <- hnf t+  case ht of+    Te'Abs _ b -> hnf =<< subst b hu+    _ -> return $ Te'App ht hu+hnf (Te'Spe t a) = do+  ht <- hnf t+  case ht of+    Te'Lam b -> hnf =<< subst b a+    _ -> return $ Te'Spe ht a+hnf t = return t  nf :: Te -> S Te nf (Te'Abs a f) = do   (x, t) <- unbind f   nt <- nf t   bt <- boxTe nt-  return $ Te'Abs a $ unbox $ bind x bt+  fmap (Te'Abs a) $ unbox $ bind x bt nf (Te'App t u) = do   nt <- nf t   nu <- nf u   case nt of-    Te'Abs _ f -> nf $ subst f u+    Te'Abs _ f -> nf =<< subst f u     _ -> return $ Te'App nt nu nf (Te'Lam f) = do   (x, t) <- unbind f   nt <- nf t   bt <- boxTe nt-  return $ Te'Lam $ unbox $ bind x bt+  fmap Te'Lam $ unbox $ bind x bt nf (Te'Spe t a) = do   nt <- nf t   case nt of-    Te'Lam f -> nf $ subst f a+    Te'Lam f -> nf =<< subst f a     _ -> return $ Te'Spe nt a nf t = return t @@ -155,12 +160,12 @@   case mtyt of     Just tyt -> do       bt <- boxTy tyt-      return $ Just $ Ty'All $ unbox $ bind x bt+      fmap (Just . Ty'All) $ unbox $ bind x bt     Nothing -> return Nothing infer ctxt (Te'Spe t a) = do   mtyt <- infer ctxt t   case mtyt of-    Just (Ty'All f) -> return $ Just $ subst f a+    Just (Ty'All f) -> Just <$> subst f a     _ -> return Nothing  check :: Ctxt -> Te -> Ty -> S Bool@@ -204,21 +209,21 @@ type1, type2 :: S Ty term1 :: S Te type1 = do-  x <- newVar "X"-  y <- newVar "Y"-  return $ unbox $ ty'Arr (ty'Var x) (ty'Var y)+  x <- newVar "X" ty'mkFree+  y <- newVar "Y" ty'mkFree+  unbox $ ty'Arr (ty'Var x) (ty'Var y) type2 = do-  x <- newVar "X"-  y <- newVar "Y"+  x <- newVar "X" ty'mkFree+  y <- newVar "Y" ty'mkFree   let arr = ty'Arr (ty'Var x) (ty'Var y)-  return $ unbox $ ty'All x $ ty'All y $ ty'Arr arr arr+  unbox $ ty'All x $ ty'All y $ ty'Arr arr arr term1 = do-  x <- newVar "X"-  y <- newVar "Y"-  f <- newVar "f"-  a <- newVar "a"+  x <- newVar "X" ty'mkFree+  y <- newVar "Y" ty'mkFree+  f <- newVar "f" te'mkFree+  a <- newVar "a" te'mkFree   let arr = ty'Arr (ty'Var x) (ty'Var y)-  return $ unbox $ te'Lam x $ te'Lam y $ te'Abs arr f $ te'Abs (ty'Var x) a $+  unbox $ te'Lam x $ te'Lam y $ te'Abs arr f $ te'Abs (ty'Var x) a $     te'App (te'Var f) (te'Var a)  spec :: Spec
+ test/Binder3Spec.hs view
@@ -0,0 +1,334 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}++module Binder3Spec where++import Control.Lens+import Control.Monad ((<=<))+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Trans.State.Strict (evalStateT, get, modify, StateT)+import Data.List (intersperse)+-- import qualified Data.Map.Lazy as M+import Data.Text (Text)+import qualified Data.Text as T (pack)+import GHC.Generics hiding (S, to)+import Test.Hspec++import Data.Binder++newtype S a = S { runS :: StateT Int IO a }+  deriving+  ( Generic+  , Generic1+  , Functor+  , Applicative+  , Monad+  , MonadIO+  )++instance MonadNumbering S where+  type Numbering S = Int+  numbering = do+    i <- S $ get+    S $ modify succ+    return i++-- This example is stolen from one example of bindlib.+-- https://github.com/rlepigre/ocaml-bindlib/blob/master/examples/pred2.ml++data Symbol = Symbol Text Int+  deriving (Eq, Show)++data Term+  = Term'Var (Var S Term)+  | Term'Fun Symbol [Term]++data Form+  = Form'Imply Form Form+  | Form'Univ1 (Binder Term S Form)+  | Form'Univ2 Int (Binder Pred S Form)+  | Form'FVari (Var S Pred) [Term]++newtype Pred = Pred { unPred :: BinderList Term S Form }++data Proof+  = Proof'ImplyI Form (Binder Proof S Proof)+  | Proof'ImplyE Proof Proof+  | Proof'Univ1I (Binder Term S Proof)+  | Proof'Univ1E Proof Term+  | Proof'Univ2I Int (Binder Pred S Proof)+  | Proof'Univ2E Proof Pred+  | Proof'Axiom Form (Var S Proof)++pred'Arity :: Getter Pred Int+pred'Arity = to unPred . binderList'Arity+pred'makeRaw :: Box S (BinderList Term S Form) -> Box S Pred+pred'makeRaw = fmap Pred+pred'make :: VarList S Term -> Box S Form -> Box S Pred+pred'make xs t = pred'makeRaw $ bindList xs t++term'mkFree :: Var S Term -> S Term+term'mkFree = return . Term'Var+pred'mkFree :: Int -> Var S Pred -> S Pred+pred'mkFree n vp = do+  let names = if n == 1 then ["x"]+                        else flip map [1..n] $ \i -> "x" <> T.pack (show i)+  xs <- newVarList names term'mkFree+  let ts = boxList $ map term'Var xs+      p = Form'FVari vp <$> ts+  fmap Pred $ unbox $ bindList xs p+proof'mkFree :: Form -> Var S Proof -> S Proof+proof'mkFree f = return . Proof'Axiom f++term'Var :: Var S Term -> Box S Term+term'Var = boxVar+term'Fun :: Symbol -> [Box S Term] -> Box S Term+term'Fun s ts = Term'Fun s <$> boxList ts+form'Imply :: Box S Form -> Box S Form -> Box S Form+form'Imply f g = Form'Imply <$> f <*> g+form'Univ1Raw :: Box S (Binder Term S Form) -> Box S Form+form'Univ1Raw = fmap Form'Univ1+form'Univ1 :: Var S Term -> Box S Form -> Box S Form+form'Univ1 x t = form'Univ1Raw $ bind x t+form'Univ2Raw :: Int -> Box S (Binder Pred S Form) -> Box S Form+form'Univ2Raw arity = fmap $ Form'Univ2 arity+form'Univ2 :: Int -> Var S Pred -> Box S Form -> Box S Form+form'Univ2 arity x t = form'Univ2Raw arity $ bind x t+form'FVari :: Var S Pred -> [Box S Term] -> Box S Form+form'FVari x ts = Form'FVari x <$> boxList ts+proof'ImplyIRaw :: Box S Form -> Box S (Binder Proof S Proof) -> Box S Proof+proof'ImplyIRaw p b = Proof'ImplyI <$> p <*> b+proof'ImplyI :: Box S Form -> Var S Proof -> Box S Proof -> Box S Proof+proof'ImplyI p x t = proof'ImplyIRaw p $ bind x t+proof'ImplyE :: Box S Proof -> Box S Proof -> Box S Proof+proof'ImplyE p q = Proof'ImplyE <$> p <*> q+proof'Univ1IRaw :: Box S (Binder Term S Proof) -> Box S Proof+proof'Univ1IRaw = fmap Proof'Univ1I+proof'Univ1I :: Var S Term -> Box S Proof -> Box S Proof+proof'Univ1I x t = proof'Univ1IRaw $ bind x t+proof'Univ1E :: Box S Proof -> Box S Term -> Box S Proof+proof'Univ1E p q = Proof'Univ1E <$> p <*> q+proof'Univ2IRaw :: Int -> Box S (Binder Pred S Proof) -> Box S Proof+proof'Univ2IRaw arity = fmap $ Proof'Univ2I arity+proof'Univ2I :: Int -> Var S Pred -> Box S Proof -> Box S Proof+proof'Univ2I arity x t = proof'Univ2IRaw arity $ bind x t+proof'Univ2E :: Box S Proof -> Box S Pred -> Box S Proof+proof'Univ2E p q = Proof'Univ2E <$> p <*> q+proof'Axiom :: Box S Form -> Var S Proof -> Box S Proof+proof'Axiom f v = (\g -> Proof'Axiom g v) <$> f++boxTerm :: Term -> S (Box S Term)+boxTerm (Term'Var x) = return $ term'Var x+boxTerm (Term'Fun s ts) = fmap (term'Fun s) $ sequenceA $ boxTerm <$> ts+boxForm :: Form -> S (Box S Form)+boxForm (Form'Imply a b) = form'Imply <$> boxForm a <*> boxForm b+boxForm (Form'Univ1 b) = form'Univ1Raw <$> boxBinder boxForm b+boxForm (Form'Univ2 a b) = form'Univ2Raw a <$> boxBinder boxForm b+boxForm (Form'FVari x ts) = do+  let arg1 = unPred <$> boxVar x+  arg2 <- fmap boxList $ sequenceA $ boxTerm <$> ts+  boxJoin $ substList <$> arg1 <*> arg2++showTerm :: Term -> Text+showTerm (Term'Var x) = nameOf x+showTerm (Term'Fun (Symbol s _) ts) =+  s <> "(" <> mconcat (intersperse ", " $ map showTerm ts) <> ")"+showForm :: Form -> S Text+showForm (Form'Imply a b) = do+  sha <- showForm a+  shb <- showForm b+  return $ "(" <> sha <> ") => (" <> shb <> ")"+showForm (Form'Univ1 b) = do+  (x, t) <- unbind b+  sht <- showForm t+  return $ "forall_1 " <> nameOf x <> ".(" <> sht <> ")"+showForm (Form'Univ2 _ b) = do+  (x, t) <- unbind b+  sht <- showForm t+  return $ "forall_2 " <> nameOf x <> ".(" <> sht <> ")"+showForm (Form'FVari x ts) = do+  return $ nameOf x <> "(" <> mconcat (intersperse ", " $ map showTerm ts) <> ")"++eqTerm :: Term -> Term -> Bool+eqTerm (Term'Var x) (Term'Var y) = x == y+eqTerm (Term'Fun s1 ts1) (Term'Fun s2 ts2) =+  s1 == s2 && and (map (uncurry eqTerm) $ zip ts1 ts2)+eqTerm _ _ = False+eqForm :: Form -> Form -> S Bool+eqForm (Form'Imply a1 b1) (Form'Imply a2 b2) = do+  ca <- eqForm a1 a2+  cb <- eqForm b1 b2+  return $ ca && cb+eqForm (Form'Univ1 b1) (Form'Univ1 b2) = eqBinder eqForm b1 b2+eqForm (Form'Univ2 a1 b1) (Form'Univ2 a2 b2) = do+  c <- eqBinder eqForm b1 b2+  return $ a1 == a2 && c+eqForm (Form'FVari x1 ts1) (Form'FVari x2 ts2) =+  return $ x1 == x2 && and (map (uncurry eqTerm) $ zip ts1 ts2)+eqForm _ _ = return False++data BadProof+  = BadProof'Imply+  | BadProof'ImplyDifferForm Form Form+  | BadProof'Univ1+  | BadProof'Univ2++showBadProof :: BadProof -> S Text+showBadProof BadProof'Imply = return "BadProof'Imply"+showBadProof (BadProof'ImplyDifferForm a b) = do+  sha <- showForm a+  shb <- showForm b+  return $ "BadProof'ImplyDifferForm (" <> sha <> ") (" <> shb <> ")"+showBadProof BadProof'Univ1 = return "BadProof'Univ1"+showBadProof BadProof'Univ2 = return "BadProof'Univ2"++typeInfer :: Proof -> S (Either BadProof Form)+typeInfer = unbox <=< fn+ where+  fn :: Proof -> S (Box S (Either BadProof Form))+  fn (Proof'ImplyI f p) = do+    ax <- newVar (p ^. binder'Name) $ proof'mkFree f+    tax <- proof'mkFree f ax+    pr <- subst p tax+    ber <- fn pr+    er <- unbox ber+    case er of+      Right r -> do+        bf <- boxForm f+        br <- boxForm r+        return $ Right <$> form'Imply bf br+      Left err -> return $ pure $ Left err+  fn (Proof'ImplyE p1 p2) = do+    mf1' <- unbox =<< fn p2+    mf2' <- unbox =<< fn p1+    case (mf1', mf2') of+      (Right f1', Right (Form'Imply f1 f2)) -> do+        b <- eqForm f1 f1'+        if b then fmap Right <$> boxForm f2+             else return $ pure $ Left $ BadProof'ImplyDifferForm f1 f1'+      _ -> return $ pure $ Left BadProof'Imply+  fn (Proof'Univ1I p) = do+    t <- newVar (p ^. binder'Name) term'mkFree+    te <- term'mkFree t+    pr <- subst p te+    ef <- unbox =<< fn pr+    case ef of+      Right f -> do+        bf <- boxForm f+        return $ Right <$> form'Univ1 t bf+      Left err -> return $ pure $ Left err+  fn (Proof'Univ1E p t) = do+    mf <- unbox =<< fn p+    case mf of+      Right (Form'Univ1 b) -> do+        f <- subst b t+        fmap Right <$> boxForm f+      Right _ -> return $ pure $ Left BadProof'Univ1+      Left err -> return $ pure $ Left err+  fn (Proof'Univ2I arity f) = do+    t <- newVar (f ^. binder'Name) $ pred'mkFree arity+    pr <- pred'mkFree arity t+    eg <- unbox =<< fn =<< subst f pr+    case eg of+      Right g -> do+        bg <- boxForm g+        return $ fmap Right $ form'Univ2 arity t bg+      Left err -> return $ pure $ Left err+  fn (Proof'Univ2E p p0) = do+    mf <- unbox =<< fn p+    case mf of+      Right (Form'Univ2 arity b) -> if arity == p0 ^. pred'Arity+        then do+          f <- subst b p0+          fmap Right <$> boxForm f+        else return $ pure $ Left BadProof'Univ2+      Right _ -> return $ pure $ Left BadProof'Univ2+      Left err -> return $ pure $ Left err+  fn (Proof'Axiom f _) = fmap Right <$> boxForm f++typeCheck :: Proof -> Form -> S Bool+typeCheck p f0 = do+  ef <- typeInfer p+  case ef of+    Right f -> eqForm f0 f+    _ -> return False+++leq :: S (Box S Pred)+leq = do+  u <- newVar "u" term'mkFree+  v <- newVar "v" term'mkFree+  let bu = term'Var u+      bv = term'Var v+  x <- newVar "X" $ pred'mkFree 1+  let bl = unPred <$> boxVar x+  p1 <- bindListApply bl $ boxList [bu]+  p2 <- bindListApply bl $ boxList [bv]+  return $ fmap Pred $ bindList [u, v] $ form'Univ2 1 x $ form'Imply p1 p2++equalTransitive :: S Form+equalTransitive = do+  q <- leq+  x <- newVar "x" term'mkFree+  y <- newVar "y" term'mkFree+  z <- newVar "z" term'mkFree+  let bx = term'Var x+      by = term'Var y+      bz = term'Var z+      bl = fmap unPred q+  p1 <- bindListApply bl $ boxList [bx, by]+  p2 <- bindListApply bl $ boxList [by, bz]+  p3 <- bindListApply bl $ boxList [bx, bz]+  unbox $ form'Univ1 x $ form'Univ1 y $ form'Univ1 z $+    form'Imply p1 $ form'Imply p2 p3++equalTransitiveProof :: S Proof+equalTransitiveProof = do+  q <- leq+  x <- newVar "x" term'mkFree+  y <- newVar "y" term'mkFree+  z <- newVar "z" term'mkFree+  let bx = term'Var x+      by = term'Var y+      bz = term'Var z+      bl = fmap unPred q+  f <- bindListApply bl $ boxList [bx, by]+  uf <- unbox f+  h1 <- newVar "h1" $ proof'mkFree uf+  g <- bindListApply bl $ boxList [by, bz]+  ug <- unbox g+  h2 <- newVar "h2" $ proof'mkFree ug+  px <- newVar "X" $ pred'mkFree 1+  p <- bindListApply (unPred <$> boxVar px) $ boxList [bx]+  up <- unbox p+  h3 <- newVar "h3" $ proof'mkFree up+  unbox $ proof'Univ1I x $ proof'Univ1I y $ proof'Univ1I z $+    proof'ImplyI f h1 $ proof'ImplyI g h2 $+    proof'Univ2I 1 px $ proof'ImplyI p h3 $+    proof'ImplyE (proof'Univ2E (boxVar h2) (boxVar px)) $+    proof'ImplyE (proof'Univ2E (boxVar h1) (boxVar px)) (boxVar h3)++spec :: Spec+spec = describe "leq" $ do+  it "forms correctly" $ do+    let r = "forall_1 x.(forall_1 y.(forall_1 z.((forall_2 X.((X(x)) => (X(y)))) => ((forall_2 X.((X(y)) => (X(z)))) => (forall_2 X.((X(x)) => (X(z))))))))"+    flip shouldReturn r $ flip evalStateT 0 $ runS $ do+      f <- equalTransitive+      showForm f+  it "infers type soundly" $ do+    let r = "forall_1 x.(forall_1 y.(forall_1 z.((forall_2 X.((X(x)) => (X(y)))) => ((forall_2 X.((X(y)) => (X(z)))) => (forall_2 X.((X(x)) => (X(z))))))))"+    flip shouldReturn r $ flip evalStateT 0 $ runS $ do+      ef <- typeInfer =<< equalTransitiveProof+      case ef of+        Right f -> showForm f+        Left bp -> showBadProof bp+  it "checks correctly" $ do+    let r = True+    flip shouldReturn r $ flip evalStateT 0 $ runS $ do+      p <- equalTransitiveProof+      f <- equalTransitive+      typeCheck p f