私は名前の種類の上にパラメータ化ラムダ計算における用語のこの表現を持っている:パラメータ化されたラムダ条件はMonadですか?
{-# LANGUAGE DeriveFunctor #-}
data Lambda a = Var a | App (Lambda a) (Lambda a) | Lam a (Lambda a)
deriving Functor
Lambda
はモナドのインスタンスを行うことができる場合、私は不思議でしたか?私は次のようなものがjoin
の実現のために働くかもしれないと考えた:
joinT :: Lambda (Lambda a) -> Lambda a
joinT (Var a) = a
joinT (fun `App` arg) = joinT fun `App` joinT arg
joinT (Lam n body) = ?
第三のケースで、私は全く手掛かりを持っている...しかし、それは可能なはず - ラムダ用語のこの無名の表現は、撮影しましたDe Bruijn Notation as a Nested Datatypeから、モナド(Maybe
がこの表現に結合および遊離の変数を区別するために使用される)のインスタンスである:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveFunctor #-}
data Expr a
= V a
| A (Expr a) (Expr a)
| L (Expr (Maybe a))
deriving (Show, Eq, Functor)
gfoldT :: forall m n b.
(forall a. m a -> n a) ->
(forall a. n a -> n a -> n a) ->
(forall a. n (Maybe a) -> n a) ->
(forall a. (Maybe (m a)) -> m (Maybe a)) ->
Expr (m b) -> n b
gfoldT v _ _ _ (V x) = v x
gfoldT v a l t (fun `A` arg) = a (gfoldT v a l t fun) (gfoldT v a l t arg)
gfoldT v a l t (L body) = l (gfoldT v a l t (fmap t body))
joinT :: Expr (Expr a) -> Expr a
joinT = gfoldT id (:@) Lam distT
distT :: Maybe (Expr a) -> Expr (Maybe a)
distT Nothing = Var Nothing
distT (Just x) = fmap Just x
joinT
はinstance Monad Expr
に十分である。
instance Applicative Expr where
pure = Var
ef <*> ea = do
f <- ef
a <- ea
return $ f a
instance Monad Expr where
return = Var
t >>= f = (joinT . fmap f) t
さらに表現との間の以下の二つの変換関数と仮定:
unname :: Lamba a -> Expr a
とname :: Expr a -> Lambda a
を。我々は2種類のコンストラクタ間の同型を利用することにより、ラムダのためjoin
を実装することができ、これらの場合:
joinL :: Lambda (Lambda a) -> Lambda a
joinL = name . joinT . uname . fmap uname
しかし、これは非常に複雑なようです。もっと簡単な方法があるのですか、何か重要なものを逃していますか?
編集:ここでは、私が仕事をするだろうと思った機能name
とuname
です。コメントと答えに指摘されているように、a
には同形を破るEq
という制約が本当に必要です。
foldT :: forall n b.
(forall a. a -> n a) ->
(forall a. n a -> n a -> n a) ->
(forall a. n (Maybe a) -> n a) ->
Expr b -> n b
foldT v _ _ (V x) = v x
foldT v a l (A fun arg) = a (foldT v a l fun) (foldT v a l arg)
foldT v a l (L body) = l (foldT v a l body)
abstract :: Eq a => a -> Expr a -> Expr a
abstract x = L . fmap (match x)
match :: Eq a => a -> a -> Maybe a
match x y = if x == y then Nothing else Just y
apply :: Expr a -> Expr (Maybe a) -> Expr a
apply t = joinT . fmap (subst t . fmap V)
uname :: Eq a => Lambda a -> Expr a
uname = foldL V A abstract
name :: Eq a => Expr a -> Lambda a
name e = nm [] e where
nm vars (V n) = Var n
nm vars (A fun arg) = nm vars fun `App` nm vars arg
nm vars (L body) =
Lam fresh $ nm (fresh:vars) (apply (V fresh) body) where
fresh = head (names \\ vars)
names :: [String]
names = [ [i] | i <- ['a'..'z']] ++ [i : show j | j <- [1..], i <- ['a'..'z'] ]
私はフレームワークに精通していませんが、 'name'、' unname'がどのように動作するのか分かりません。あなたはどのように変わりますか? 'Lam(\ x - > x + 1)(Var(\ y - > 2 * y)):: Lambda(Int-> Int)'を 'Expr(Int-> Int)'に変換しますか?これらのタイプは本当に同形ですか?この変換で関数に 'Eq'が必要なのでしょうか? (ちょうどここで推測する...) – chi
あなたは正しいです... 'a'は' 'Eq''が拘束されている必要があります。 Isomorphismを破ることはできますか? – jules
制約と「Monads」がうまく混ざり合っていないので、私はそれを言いました。例えば。 'Set'はモナドでなければなりませんが、' Ord'の制約がそれを防止します。また、 'Lam fresh ...'は 'Lambda a'ではなく' Lambda String'値のように見えます。それは本当にタイプチェックですか? – chi