0

一般来说,我是 Monads 和 Haskell 的新手,并试图了解如何在使用它们时返回一个值。我的代码如下所示:

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"
4

1 回答 1

6

你需要的是

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

您构造State MyState Baction fooC a (C 0),将其解包以获取一个函数,并将该函数应用于初始状态。由于此示例中未使用状态,因此您也可以在此处使用undefined而不是MyState "whatever",但通常,您需要提供有意义的初始状态。

State MyState B不是元组,它与函数同构

MyState -> (B, MyState)

但是该函数被包装在 a 中newtype(细节因 monad 转换器库包和版本而异),因此要访问应用于初始状态的该函数的结果,您需要一个解包函数。对于State,有

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

它为您提供了返回该对的函数,

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

这为您提供了由 组成的函数fst,因此最终状态被丢弃,并且

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

它与 组成函数snd,因此只返回最终状态。

于 2012-11-22T16:09:45.993 回答