2014-03-30 37 views
2

我明白如何使用monads,但我没有真正掌握如何创建monad。所以我正在重新创建一个国家monad的旅程。创建我自己的状态monad

到目前为止,我创建了一个新类型的托托(法语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' 
+0

虽然完全正确的,我找到了'Monad'实例声明困惑,因为你用'托托了'作为类型,其中'了'是表示状态的类型变量,但是在实现中,您将'a'绑定到monad *值*,并将'x'和'c'绑定到状态。如果你使用's'作为类型变量,'s'和's''作为状态绑定,那么它就不那么令人困惑了。 – pat

回答

4

让我们用ghci中视察种:

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

Toto有两个类型参数:环境类型和返回t YPE。如果r是环境,则Toto r将是monad类型的构造函数。

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

TotoReader有两个类型参数:单子类型构造和环境类型,这在我们的情况下,分别为Toto rr

因此,实例声明应该是这样的:

instance TotoReader (Toto r) r where 
    get = toto $ \x -> (x, x) 
+0

谢谢,我忘了,如果名称不同,类型不能相同。 –