2012-11-22 36 views
0

我是一般的Monads和Haskell的新手,并试图了解如何在使用它们时返回一个值。我的代码看起来像下面这样:用状态monad返回一个值

foo :: A -> B 
foo a = do b <- fooC a (C 0) 
      -- want to return just (B "b") 

fooC :: A -> C -> State MyState B 
fooC a c = return (B "b") 

我试着用snd (snd b),但显然State MyState B不是一个元组?我如何返回所需的值(B "b")

编辑:以丹尼尔的意见考虑进去,重写如下:

data MyState = MyState String 
data C = C Int 
foo :: String -> String 
-- want to return just "b" 
foo a = evalState (fooC a) (C 0) 

fooC :: String -> Int -> State MyState String 
fooC a c = return "b" 

这仍然会导致编译错误:

Couldn't match expected type `State s0 String' 
      with actual type `Int -> State MyState String' 
In the return type of a call of `fooC' 
Probable cause: `fooC' is applied to too few arguments 
In the first argument of `evalState', namely `(fooC a)' 
In the expression: evalState (fooC a) (C 0) 

编辑2:固定!最终版本看起来如下:

import Control.Monad.State 
data MyState = MyState String 
data C = C Int 
foo :: String -> String 
-- want to return just (B "b") 
foo a = evalState (fooC a (C 0)) (MyState "whatever") 

fooC :: String -> C -> State MyState String 
fooC a c = return "b" 

main = print(foo("test")) 
-- prints "b" 

回答

6

你需要的是

foo a = evalState (fooC a (C 0)) (MyState "whatever") 

您构建State MyState B行动fooC a (C 0),解开它获得的功能,并应用功能的初始状态。由于在此示例中未使用状态,因此您可以在此使用undefined而不是MyState "whatever",但通常情况下,您需要提供有意义的初始状态。

State MyState B不是一个元组,它是同构的函数

MyState -> (B, MyState) 

但该功能被包裹在一个newtype(细节由单子变压器库包和版本而变化),所以访问的,其结果函数应用于初始状态,则需要展开功能。对于State,有

runState :: State s r -> (s -> (r,s)) 

它给你的函数返回一对,

evalState :: State s r -> (s -> r) 

,让您与fst组成的功能,所以最终状态被丢弃,

execState :: State s r -> (s -> s) 

snd组成函数,所以只返回最终状态。

+0

这似乎没有工作。看到我的文章中的编辑。 –

+0

哎呀,不好意思解析我的错误。更新。 –

+0

工作!谢谢丹尼尔! –