2013-08-28 17 views
6

なぜMonadTransリフトの戻り値がモナドに制限されていないのはなぜですか?

class MonadTrans t where 
    lift :: (Monad m, Monad (t m)) => m a -> t m a 
--     ^^^^^^^^^^^ 

の代わりに、これは(Why aren't monad transformers constrained to yield monads?における提案とは異なり)のHaskell 98であり、結果は常にあることを保証

class MonadTrans t where 
    lift :: Monad m => m a -> t m a 

電流として定義されていませんモナド。モナド変圧器がモナドでないものを作ることが許される理由はありますか?

+1

クラスを作ることだった疑いがありますか?それは厳密にはあまり一般的ではないでしょうし、私はそれから何の利益も見ません。 –

+3

@ JohnL主に['MonadTrans'の法律](http://hackage.haskell.org/packages/archive/transformers/0.3.0.0/doc/html/Control-Monad-Trans-Class.html#t:MonadTrans)モナドで表現されるので、結果はモナドでなければなりません。もしそうでなければ、法律は表現することさえできません。しかし、bheklilrは答えに良い点を示し、それに基づいて私は 'Monad' - >' Applicative'トランスを生成する[例](http://stackoverflow.com/a/18495255/1333025)を作ったのです。しかし、これは異なる法律を定式化する必要があることを意味します。 –

答えて

4

MonadMonadに変換する代わりに、MonadTransMonadを別のものに変換すると思います。 Monadを変換するものを書くかもしれないし、liftを定義できますが、>>=returnを定義することはできませんので、より一般化されています。ほとんどの(すべてではないにしても)MonadTransのインスタンスはMonadになりますので、コンパイラがそれをうまく処理するので実際には問題はありません。

+0

個人的な知識はありませんが、これが理由だと思います。 'Monad'ではない' Functor'や 'Applicative'の' MonadTrans'インスタンスがほしいかもしれないと思われます。 –

+0

@JohnLこれはまさに私の推論でした。私はソースを知らないので、私はソースを知らないので(誰もがそのドキュメントを自由に投稿することができれば)、MonadTransは2つではなく1つのモナドでしか動作しないという意味になります。 – bheklilr

6

bheklilrの答えは、モナド変圧器がモナドでないものを生成する例を私に与えました。モナドでないもののよく知られている例はZipListです。

import Control.Applicative 
import Control.Arrow ((***)) 
import Control.Monad 
import Control.Monad.Trans 

-- | A list where each step is produced by a monadic action. 
data ListT m a = Nil | Cons (m (a, ListT m a)) 

実際にはモナドストリームです。そして、それは簡単にFunctorApplicative

instance Monad m => Functor (ListT m) where 
    fmap f Nil  = Nil 
    fmap f (Cons k) = Cons $ (f *** fmap f) `liftM` k 
instance Monad m => Applicative (ListT m) where 
    pure x = Cons $ return (x, pure x) 
    Cons mf <*> Cons mx = Cons $ do 
     (f, fs) <- mf 
     (x, xs) <- mx 
     return (f x, fs <*> xs) 
    _  <*> _  = Nil 

が、明らかではないモナドにすることができます。したがって、MonadTransというインスタンスは、モナドをApplicativeだけに変換します。

instance MonadTrans ListT where 
    lift mx = Cons $ (\x -> (x, lift mx)) `liftM` mx 

(この全体のことは私がコンジット-余分の実験ZipSinkも素敵な一例であることを実感しました。)


しかし、これは別の問題を提起:私たちは、このようなをしたい場合変圧器、どの法律に従うべきですか? MonadTransのための法律がそう私たちのケースでは、我々は、私はと言うことは、他の2つの答えに反対するつもりだ

lift (f `liftM` x) = fmap f (lift x) 

lift . return  = pure 
lift (m `ap` f)  = lift m <*> lift f 
+0

最後のモナドレイヤーに 'ListT'をラップすると、それはモナド、特に[" ListT done right "](http://www.haskell.org/haskellwiki/ListT_done_right)です。 –

+0

@GabrielGonzalezはい、「ListT」を思い出したことが私のインスピレーションでした。しかし、私の 'ListT'は、' 'ZipList'(http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Applicative.html)とちょうど同じように' '純粋な' 'と' <*> 'を異なって定義しています。 #t:ZipList)は '[]'とは異なります。したがって、有効なモナドインスタンスはありません。 –

3

ような何かを望むことができる

lift . return = return 
lift (m >>= f) = lift m >>= (lift . f) 

のように定義されています結果はモナドでなければなりません。それ以外の理由は、liftが従うべき合理的な法律がない理由です。

:あなたは、彼らが2つのKleisliカテゴリ間ファンクタ法則です実現する場合、これらの法律は、より多くの意味を作る

lift (return x) = return x 

lift (m >>= f) = lift m >>= \r -> lift (f r) 

liftは、それは、次の2つの法律に従わなければならないことを意味し、モナド射ことになっています

-- i.e. "fmap id = id" 
(lift .) return = return 

-- i.e. "fmap (f . g) = fmap f . fmap g" 
(lift .) (f >=> g) = (lift .) f >=> (lift .) g 

出力をモナドに制限しないと、これらの法則は無効になり、が正しく実装されたことを確認する賢明な方法はありません。

私は、本当の理由は、あなたが結果がモナドであることを確認したいのはなぜHaskell98

+0

私は 'lift ::(Monad m、Monad(t m))=> m a - > t m a'という考えをH98と考えています。ですから、 'ZipListT'のようなものでは、' lift ::(Applicative f)=> f a - > t f a'のような別の変圧器を使うべきだとお勧めします。 –

+0

@PetrPudlák私は制約の欠如の本当の理由を知らないので、私はちょうど推測しています。適用変圧器はどんな法律に従うでしょうか? –

+0

私は応用変圧器が適用法に従うべきであると思います。また、変圧器変圧器はファンクション法のみに従う必要があります。ほとんどの場合、それは尖ったファンクタなので、「リフト」となります。純粋な=純粋な」は依然として有効であるべきである。私はそれがうまくいくと思う。 –

関連する問題