【问题标题】:The state monad and learnyouahaskell.com状态单子和 learnyouahaskell.com
【发布时间】:2012-03-14 08:08:04
【问题描述】:

我正在阅读Learn You a Haskell's guide on the state monad,但由于堆栈示例无法编译,我无法理解它。在指南中,他使用了以下代码:

import Control.Monad.State  

type Stack = [Int]

pop :: State Stack Int  
pop = State $ \(x:xs) -> (x,xs)  

push :: Int -> State Stack ()  
push a = State $ \xs -> ((),a:xs) 

虽然我理解它应该做什么,但它不会编译。我不知道为什么。错误信息是:

Stack.hs:6:7: Not in scope: data constructor `State'

Stack.hs:9:10: Not in scope: data constructor `State'

这对我来说毫无意义,因为据我所知,“状态”实际上是一个数据构造函数,定义为

newtype State s a = State { runState :: s -> (a,s) }

指南是否“错误”,如果是,我该如何解决?

【问题讨论】:

  • Control.Monad.State 不导出State 构造函数,使用state(小写s)。
  • @Vitus 不错,我不知道that function 被导出了。我认为您应该将其写为答案而不是评论。
  • @Vitus:那很奇怪,因为他的代码实际上可以在我的 Windows 上的 GHCI 6.12.3 上编译并运行良好。
  • @Riccardo State 已弃用,取而代之的是 StateT。由于State monad 可以在Identity monad 上定义为StateT,所以它现在是一个类型同义词并且没有State 数据构造函数。
  • 好吧,那只是因为learnyouahaskell老了? :)

标签: haskell monads


【解决方案1】:

正如我在 cmets 中提到的,您应该使用 state 而不是 State


问题在于State 不是独立的数据类型(或者更确切地说是newtype),而是应用于Identity monad 的StateT 转换器。实际上,它被定义为

type State s = StateT s Indentity

因为它只是 type 的同义词,所以它不能有 State 构造函数。这就是Control.Monad.State 使用state 的原因。

【讨论】:

  • 这不再有效。有人知道正确的语法吗?
【解决方案2】:

接受的答案已经提到使用来自Control.Monad.Statestate 函数,而不是State 类型。但是,如果您只是在 ghci 中尝试接受的答案并加载相关的 mtl 包,它仍然会失败:

Prelude Control.Monad.State> push a = state $ \xs -> ((), a:xs)

<interactive>:5:1: error:
    • Non type-variable argument in the constraint: MonadState [a] m
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        push :: forall a (m :: * -> *). MonadState [a] m => a -> m ()

要解决这个问题,这里有两个选项:

  1. 要么指定函数的类型签名(无论如何你都应该这样做)。
  2. 添加FlexibleContexts 编译器扩展,如错误中所述。

我们可以指定类型签名:

module LearnYouAHaskell where

import Control.Monad.State as State

push :: Int -> State.State [Int] ()
push a = State.state $ \xs -> ((), a:xs)

上面的编译正常,功能符合预期。

或者我们可以添加语言扩展,以便推断函数类型。

{-# LANGUAGE FlexibleContexts #-}
module LearnYouAHaskell where

import Control.Monad.State as State

push a = State.state $ \xs -> ((), a:xs)

这也可以正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2019-12-13
    • 2016-09-17
    相关资源
    最近更新 更多