Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 状态Monad的实现_Haskell - Fatal编程技术网

Haskell 状态Monad的实现

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

我正在编写一个简单的示例来实现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:: 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

  • 您需要正确缩进代码。您似乎希望打印a1是外部do块的一部分,而不是内部do块的一部分。如果没有缩进,编译器就无法理解这一点
  • 您正在(尝试)手动执行状态线程,但是
    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)