2014-03-30 40 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

謝謝,我忘了,如果名稱不同,類型不能相同。 –