繁体   English   中英

使用状态monad更新和返回多个值

[英]Updating and returning multiple values using the state monad

我正在为我正在写的合同DSL进行合同评估。 合同DSL基于Simon Peyton Jones财务合并人文件。 我对Haskell和monad还是比较陌生,并且在State monad方面遇到问题。 如下所示,递归调用evalAll2,直到到达End为止。 我在记录ContractSt中有三个变量,它们在调用evalC时更新,people是合同各方的数目(由唯一的int标识),余额是合同中的金额,所有者是拥有者合同。 合同的评估如下:

bettingContract :: Contract
bettingContract 
          = until (Date (2018,12,13)) 
                (cashIn 20 1 
                    (cashIn 20 2 
                        (time (Date (2018,12,15))
                            (pay 1 2 40 End)
                        End)
                    End)                            
                End)
            End

c1 = evalAll(bettingContract)

我要代码执行的操作是输出正在评估的合同,“输出”是基于特定操作生成的消息,并在评估合同后显示ContractSt的值。 主要问题是我得到了:

<interactive>:12:1: error:
    * No instance for (Show
                         (Control.Monad.Trans.State.Lazy.StateT
                            ContractSt
                            Data.Functor.Identity.Identity
                            ()))
        arising from a use of `print'

当我尝试评估合同时。 我知道我必须使用evalState返回最终结果(这是我想要的),并且我不是在尝试为show for()创建实例,而是返回最终状态以及合同,以及输出是我最困难的地方。

data ContractSt = ContractSt { 
people :: [Person], balance :: Money, owner :: Person } deriving (Show)

evalAll :: Contract -> (Contract, OP, State ContractSt ()
evalAll c = evalAll2 c [] initialState 

evalAll2 :: Contract -> OP -> State ContractSt () -> (Contract, OP, State 
ContractSt ()
evalAll2 c o s
    | c == End = (c, o, s)
    | otherwise = evalAll2 nc (o ++ no) ns
        where
            (nc, no,ns) = evalC c 

我没有读懂您的动机,但是如果您的问题是如何转换3元组的最后一个元素,则可以轻松地为此编写一个函数:

mapLast3 f (a,b,x) = (a, b, f x)

这是一个完整的示例,其中通过以硬编码的初始状态运行计算,将三元组(Int, Double, State String ())转换为(Int, Double, String)

import Control.Monad.State

mapLast3 :: (x -> c) -> (a,b,x) -> (a,b,c)
mapLast3 f (a,b,x) = (a, b, f x)

myExecutor :: State String () -> String
myExecutor f = execState f "Hello"

execLast3 :: (a, b, State String ()) -> (a, b, String)
execLast3 = mapLast3 myExecutor

myStateFunction :: State String ()
myStateFunction = modify (++ " World")

myOriginalTuple :: (Int, Double, State String ())
myOriginalTuple = (42, 3.14, myStateFunction)

myFinalTuple :: (Int, Double, String)
myFinalTuple = execLast3 myOriginalTuple

main = print myFinalTuple

它将打印(42,3.14,"Hello World")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM