实现状态monad时数据构造函数错误?

时间:2017-02-09 09:49:24

标签: haskell monads

我正在通过州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)"

我错过了一些基本的东西吗?

2 个答案:

答案 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)

或者,您可以通过其putget函数将其作为monad使用,而不是使用State的这种低级视图:

pop :: State Stack Int
pop = do
  (x : xs) <- get
  put xs
  return x