我正在通过州monad here并且我正在努力实施:
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.State
type Stack = [Int]
pop :: State Stack Int
pop = State $ (x : xs) -> (x, xs)
但是我收到以下错误:
"Data constructor not in scope:
State :: ([t0] -> (t0, [t0])) -> State Stack Int
Perhaps you meant one of these:
‘StateT’ (imported from Control.Monad.State),
variable ‘state’ (imported from Control.Monad.State)"
我错过了一些基本的东西吗?
答案 0 :(得分:6)
不,你不是。教程简化了一些事情(或者它可能只是过时了 - 我不能回过头来知道这两个中的哪一个)已经过时了。 Control.Monad.State
定义了monad 转换器 StateT
。它还导出一个类似于教程教你的简单类型同义词
type State s a = StateT s Identity a
但是,这确实意味着构造函数不是State
,而是StateT
(并且它具有通用签名)。值得庆幸的是,你现在不需要担心太多。
State
,您可以使用state
函数并假装它具有签名state :: (s -> (a,s)) -> State s a
(实际上,它具有更一般的签名 - 您在错误消息中遇到此问题)。State
,只需使用runState :: State s a -> s -> (a,s)
代替模式匹配。从你给出的例子中可以看出:
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.State
type Stack = [Int]
pop :: State Stack Int
pop = state $ \(x : xs) -> (x, xs)
答案 1 :(得分:2)
为什么假设State a
的接口是通过包装函数s -> (a, s)
的数据构造函数?这是实现 State的一种简单方法,但是没有提供该接口。相反,请使用Control.Monad.State中提供的构造。
一个简单的改变就是使用为此目的设计的小写state
函数:
pop :: State Stack Int
pop = state $ \(x : xs) -> (x, xs)
或者,您可以通过其put
和get
函数将其作为monad使用,而不是使用State的这种低级视图:
pop :: State Stack Int
pop = do
(x : xs) <- get
put xs
return x