Haskell 状态Monad的实现
我正在编写一个简单的示例来实现Haskell中的状态monad。我使用记录语法创建了一个数据类型GlobState。函数incr1、incr2和incr3用于增加相应的记录元素。我写的代码是:Haskell 状态Monad的实现,haskell,Haskell,我正在编写一个简单的示例来实现Haskell中的状态monad。我使用记录语法创建了一个数据类型GlobState。函数incr1、incr2和incr3用于增加相应的记录元素。我写的代码是: module StateExample where import Control.Monad.State data GlobState = GlobState { c1 :: Int, c2:: Int, c3:: Int} deriving (Show) newGlobState:: GlobSta
module StateExample where
import Control.Monad.State
data GlobState = GlobState { c1 :: Int, c2:: Int, c3:: Int} deriving (Show)
newGlobState:: GlobState
newGlobState = GlobState { c1=0,c2=0,c3=0 }
--incr1 :: State GlobState ()
incr1 = do
gets c1
modify (+1)
--incr2 :: State GlobState ()
incr2 = do
gets c2
modify(+1)
incr3 = do
gets c3
modify(+1)
main = do
let ((),a1) = flip runState newGlobState $ do
x<- incr1
y<- incr2 x
z<- incr1 y
return z
print a1
至少你的类型是对的
incr1 :: State GlobState ()
incr1 = modify (\state -> state {c1 = 1 + c1 state})
如果您在状态Int()
下工作,那么您的修改(+1)
就可以了,但我们不是。您似乎认为,get
会将以下行集中到状态的特定字段上,但事实并非如此
incr2
和incr3
需要进行类似的更改
关于main
:
state
的关键在于它的一元/应用程序管道可以为您执行此操作这是有效的代码,也许你可以从中构建
module StateExample where
import Control.Monad.State
data GlobState = GlobState { c1 :: Int, c2:: Int, c3:: Int} deriving (Show)
newGlobState:: GlobState
newGlobState = GlobState { c1=0,c2=0,c3=0 }
incr1 :: State GlobState ()
incr1 = modify (\g -> g {c1 = c1 g +1})
incr2 :: State GlobState ()
incr2 = do
modify (\g -> g {c2 = c2 g +1})
incr3 :: State GlobState ()
incr3 = do
modify (\g -> g {c3 = c3 g +1})
main :: IO ()
main = do
let a1 = flip execState newGlobState $ do
incr1
incr2
incr1
print a1
这里的类型是一个问题-在这种情况下:
modify :: (GlobState -> GlobState) -> State GlobState ()
这是一个问题,因为:
modify (+1) :: (Int -> Int) -> State Int ()
因此,您需要按照如下方式编写函数:
incr1 = modify (\GlobState c1 c2 c3 -> GlobState (c1 + 1) c2 c3)
或者,您可以分别获取和设置状态:
incr1 = do
(GlobState c1 c2 c3) <- get
put (GlobState (c1 + 1) c2 c3)
incr1=do
(globstatec1 c3)您可以从包中使用
incr1 = modify c1 (+1)
incr2 = modify c2 (+1)
incr3 = modify c3 (+1)
我认为这并不是故意的。您也可以使用(`execState`newGlobState)
而不是翻转运行状态的元组上的模式匹配。我尝试尽可能接近原始代码。但是你是对的,使用execState
是一种改进,所以我改变了这一点。我喜欢小节样式,但保留了原始代码使用的样式。作为补充,我们还有另一个理由不在Haskell source中使用制表符:它在StackOverflow上的格式不好!我详细阐述了fclabels
在相关问题中的用法。
incr1 = do
(GlobState c1 c2 c3) <- get
put (GlobState (c1 + 1) c2 c3)
incr1 = modify c1 (+1)
incr2 = modify c2 (+1)
incr3 = modify c3 (+1)