2013-02-22 119 views
2

原始问题

最近版本的Haskell(> 7.4.2?)带有一个mtl包,它不再提供一个状态构造函数本身,而是提供一个状态函数。wikibooks中的Haskell状态示例:修复每个当前Haskell?

这打乱了国家的例子在维基页面在这里:http://en.wikibooks.org/wiki/Haskell/Understanding_monads/State

有人可以显示如何修改以下标题的例子“引进国家”?这是小功能rollDie和rollDice。

在页面的前面有一个注释框,标题为“State Monad的定义”,它总体上描述了要做什么,但对我来说太模糊了。

另外,我并不清楚导入和包是如何工作的,所以对这个例子来说一个可能相关的事情可能是指定需要什么导入,因为它们也可能已经改变。

谢谢!

源代码

------- Adding code for ghci01.hs------- 

-- http://en.wikibooks.org/wiki/Haskell/Understanding_monads/State 
-- Introducing State heading and below 

import Control.Monad 
import System.Random 

type GeneratorState = State StdGen 

rollDie :: GeneratorState Int 
rollDie = do generator <- get 
      let (value, newGenerator) = randomR (1,6) generator 
      put newGenerator 
      return value 

-- Test rollDie 
-- evalState rollDie (mkStdGen 0) 

rollDice :: GeneratorState (Int, Int) 
rollDice = liftM2 (,) rollDie rollDie 

-- Test rollDice 
-- evalState rollDice (mkStdGen 666) 

------- In GHCi -------- 
ghci> :l dice01.hs 
[1 of 1] Compiling Main    (dice01.hs, interpreted) 
dice01.hs:7:23: Not in scope: type constructor or class `State' 
dice01.hs:10:27: Not in scope: `get' 
dice01.hs:12:14: Not in scope: `put' 
Failed, modules loaded: none. 

附录

对于其他人谁绊倒在这里:

这个问题的主要议题是围绕非工作示例代码,并在注警告在上面引用的wikibooks页面上。该框表明对于MTL版本> 2.0.0.0,由于Control.Monad.State中的更改,某些示例代码无法工作。

我的测试涉及到基于mtl.cabal文件的Haskell Platform 2012.4.0.0,其中包括GHC 7.4.2和MTL,我迟迟未发现它是1.1.1.1。 因此,注意的警告不应该适用,但是示例代码无效无效。通过这里的答案建议的更改(更改导入Control.Monad到Control.Monad.State)确实解决了问题。但显然这是解决了一些与之前的更改有关的问题,而不是注释中引用的MTL 2.x。

我已经看过GHC 7.6.2的源代码了,在那里我根本找不到MTL库。相反,与状态相关的文件位于库/变换器/控制/ Monad/Trans /状态中。然后,我采取了一系列令人困惑的弯路,包括当前没有使用GHC的Haskell平台迟于7.4.2(即:无7.6.2)的问题。

然后我发现MTL文档(http://www.haskell.org/haskellwiki/Monad_Transformer_Library),它指向这个计算器Q &答:mtl, transformers, monads-fd, monadLib, and the paradox of choice ...哪种类型的解释了很多,至少在23年以前。

+0

我认为这些函数适用于MTL版本2.12(当前版本)。你为什么认为他们不?你可以发布你在尝试它们时得到的错误(和你的完整代码)吗? – 2013-02-22 03:10:30

+0

我已经添加了我尝试过的代码,它是从wikibooks页面复制的,我认为是逐字的。根据我指出的注释框,我相当确定它不会工作,并且错误消息(缺少状态构造函数或类)与注释所预测的一样。 – gwideman 2013-02-22 03:25:08

回答

7

上面的代码只有一个问题

Control.Monad ===> Control.Monad.State 

唯一的实时变化咬你的时候,你有什么样

foo :: State Int Int 
foo = State $ \a -> (a, a) -- This is an error 

但固定它容易:

foo :: State Int Int 
foo = state $ \a -> (a, a) 

类型构造函数State仍然存在,它只是将数据构造函数隐藏起来而支持state。这有点令人困惑,因为它们都被命名为相同的东西。

+0

啊,是的,谢谢你对这个问题本身的回答,以及关于类似命名的类型构造函数和数据构造函数之间的区别的额外提醒,这是一个常常陷入困境的陷阱。 [咳嗽]。 – gwideman 2013-02-22 10:25:02

+1

我不确定是否可以严格调用'State'类型构造函数,它现在是一个类型别名('type State s = StateT s Identity')。 – 2013-02-22 14:49:49

+1

@DanielFischer这是一个很好的观点,将它称为类型别名会更合适吗?虽然GHC不会很快地去掉别名? – jozefg 2013-02-22 16:33:50

4

该代码与State类型同义词编译得很好。你只需要

import Control.Monad.State 
+0

感谢您的回答。我不知道,但我怀疑你是第一个发型,但是我将这个复选标记授予jozefg使用ESP来确定我可能想知道一些相关的事实。很高兴+1你的答案。 – gwideman 2013-02-22 10:27:41