State Monad ExampleProblem

Rog*_*ews 4 haskell

我正在研究这个问题,之前曾问过相关问题.状态Monad的实现为了进一步优化我的代码,我试图仅使用一个增量函数来实现它.

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 }

incr :: String-> State GlobState ()
incr x = do
     modify(\g -> g {x =x g + 1})

main:: IO()
main =  do
    let a1= flip execState newGlobState $ do
        incr c1
        incr c2
        incr c1
    print a
Run Code Online (Sandbox Code Playgroud)

但在这里我得到一个错误

`x' is not a (visible) constructor field name
Run Code Online (Sandbox Code Playgroud)

我该如何删除此错误?

dan*_*anr 9

你在Haskell中遇到了一个弱点:记录不是一流的价值!实际上,像你所做的那样写作会很好,但这是不可能的.但是,您可以使用不同的库来实现所需的效果.如果您使用fclabels,它就是这样的 :

{-# LANGUAGE TemplateHaskell, TypeOperators #-}
module StateExample where

import Control.Monad.State hiding (modify)
import Data.Label (mkLabels)
import Data.Label.Pure ((:->))
import Data.Label.PureM

data GlobState = GlobState { _c1 :: Int , _c2 :: Int , _c3 :: Int } deriving Show
$(mkLabels [''GlobState])

newGlobState:: GlobState
newGlobState = GlobState { _c1 = 0, _c2 = 0, _c3 = 0 }

incr :: (GlobState :-> Int) -> State GlobState ()
incr x = modify x (+1)

main :: IO ()
main = do
    let a = flip execState newGlobState $ do
        incr c1
        incr c2
        incr c1
    print a
Run Code Online (Sandbox Code Playgroud)

这里有一些神奇的部分.我们GlobState使用相同的记录名称定义,但前缀为下划线.然后该函数 mkLabels用于TemplateHaskell为记录中的每个字段定义"镜头".这些镜头将具有相同的名称,但没有下划线.这个论点(GlobState :-> Int)incr就是这样一个镜头,我们可以使用modify从功能Data.Label.PureM 用于更新记录中定义的状态单子里面这样.我们隐藏 modifyControl.Monad.State,以避免冲突.

你可以看一下其他功能的 文档PureM 与状态单子使用其他功能,如 getsputs.

如果您尚未fclabels安装,但是您拥有该软件包中的cabal可执行文件cabal-install(如果您安装了Haskell平台,则可以获得),fclabels只需运行即可安装:

 cabal install fclabels
Run Code Online (Sandbox Code Playgroud)

如果这是您第一次运行cabal,则首先需要更新数据库:

 cabal update
Run Code Online (Sandbox Code Playgroud)