State Monad示例问题 [英] State Monad ExampleProblem

查看:54
本文介绍了State Monad示例问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究此问题,之前曾问过相关问题.州Monad的实现为了进一步完善我的代码,我尝试仅使用一个增量函数来实现它.

I am working on this problem and had previously asked related question. Implementation of State Monad To further refine my code i tried to implement it using only one increment function.

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

但是在这里我遇到了错误

But here i am getting an error

`x' is not a (visible) constructor field name

如何清除此错误?

推荐答案

您在Haskell中遇到了一个弱点:记录不是一流的值!确实,像您所做的那样写会很好,但是这是不可能的.但是,您可以使用不同的库来实现所需的效果.这是您使用时的外观 fclabels :

You have hit a weakness in Haskell: records are not first class values! Indeed, it would be very nice to write as you have done, but it is not possible. However, you can use different libraries to achieve the desired effect. This is how it looks if you use 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

这里有一些神奇的地方.我们用相同的定义 GlobState 记录名称,但下划线前.然后功能 mkLabels 使用 TemplateHaskell 为每个字段定义镜头"在记录中.这些镜头将具有相同的名称,但没有下划线. incr 的参数((GlobState:-> Int)镜头,我们可以使用 Data.Label.PureM 中的 modify 函数它会更新状态monad内以此方式定义的记录.我们躲起来从 Control.Monad.State 中进行 modify ,以避免发生冲突.

There are some magic parts here. We define the GlobState with the same record names but prependend with an underscore. Then the function mkLabels uses TemplateHaskell to define "lenses" for every field in the record. These lenses will have the same name but without the underscore. The argument (GlobState :-> Int) to incr is such a lens, and we can use the modify function from Data.Label.PureM which updates records defined this way inside the state monad. We hide modify from Control.Monad.State, to avoid collision.

你可以看看另一个中的功能文档PureM 对于可用于状态monad的其他功能,例如获取 put .

You can look at the other functions in the documentation for PureM for other functions usable with state monads, as gets and puts.

如果没有安装 fclabels ,但是从 cabal-install 软件包中获得了 cabal 可执行文件(如果安装Haskell平台),则只需运行以下命令即可安装 fclabels :

If you do not have fclabels installed, but you have the cabal executable from the cabal-install package (which you get if you install the Haskell Platform), you can install fclabels by simply running:

 cabal install fclabels

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

If this is the first time you run cabal, you first need to update the database:

 cabal update

这篇关于State Monad示例问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆