2

モナドの使い方はわかるが、モナドの作り方がよくわからない。だから私はStateモナドを再作成する旅に出ています。

これまでのところ、新しい型 Toto (フランス語で foo) を作成し、それを Monad のインスタンスにしました。現在、「リーダー機能」を追加しようとしています。「get」関数を宣言するクラス TotoReader を作成しました。しかし、インスタンス化しようとすると、すべてがバラバラになります。GHC は (m ~ r) を推定できなかったと言っています (下部の完全なコンパイル エラー)。

しかし、最上位関数 get を作成すると、すべてが正しく機能します。

では、クラスでget関数を定義するにはどうすればよいですか?それは本当に正しい方法ですか? 私が理解できないのは何ですか?

以下の私のコード

{-# OPTIONS -XMultiParamTypeClasses #-}
{-# OPTIONS -XFlexibleInstances #-}

newtype Toto s val = Toto { runToto :: s -> (val, s) }

toto :: (a -> (b,a)) -> Toto a b
toto = Toto

class (Monad m) => TotoReader m r where
    get :: m r

instance Monad (Toto a) where
    return a = toto $ \x -> (a,x)
    p >>= v  = toto $ \x ->
                    let (val,c) = runToto p x
                    in runToto (v val) c

instance TotoReader (Toto m) r where 
    get = toto $ \x -> (x, x) -- Error here

-- This is working
-- get :: Toto a b
-- get = toto $ \s -> (s,s)


pp :: Toto String String
pp = do 
    val <- get
    return $ "Bonjour de " ++ val

main :: IO ()
main = print $ runToto pp "France"

コンパイルエラー

test.hs:19:11:
    Could not deduce (m ~ r)
    from the context (Monad (Toto m))
      bound by the instance declaration at test.hs:18:10-30
      `m' is a rigid type variable bound by
          the instance declaration at test.hs:18:10
      `r' is a rigid type variable bound by
          the instance declaration at test.hs:18:10
    Expected type: Toto m r
      Actual type: Toto m m
    In the expression: toto $ \ x -> (x, x)
    In an equation for `get': get = toto $ \ x -> (x, x)
    In the instance declaration for `TotoReader (Toto m) r'
4

1 に答える 1

4

ghciを使って種類を調べてみましょう:

*Main> :k Toto
Toto :: * -> * -> *

Toto環境型と戻り型の 2 つの型パラメーターを取ります。rが環境の場合Toto r、モナド型コンストラクターになります。

*Main> :k TotoReader
TotoReader :: (* -> *) -> * -> Constraint

TotoReaderは 2 つの型パラメーターを取ります: モナド型コンストラクターと環境型で、この場合はそれぞれToto rrです。

したがって、インスタンス宣言は次のようになります。

instance TotoReader (Toto r) r where 
    get = toto $ \x -> (x, x)
于 2014-03-30T10:18:50.577 に答える