使Haskell中的一个州具有只读功能 [英] Making Read-Only functions for a State in Haskell

查看:83
本文介绍了使Haskell中的一个州具有只读功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于经常需要以半命令方式对同一条数据进行操作的许多相关功能,因此我经常会遇到使用State monad非常方便的情况.

I often end up in a situation where it's very convenient to be using the State monad, due to having a lot of related functions that need to operate on the same piece of data in a semi-imperative way.

某些功能需要读取State monad中的数据,但永远不需要更改它.在这些函数中照常使用State monad可以很好地工作,但是我忍不住放弃了Haskell的固有安全性,并复制了一种语言,其中任何函数都可以对任何东西进行变异.

Some of the functions need to read the data in the State monad, but will never need to change it. Using the State monad as usual in these functions works just fine, but I can't help but feel that I've given up Haskell's inherent safety and replicated a language where any function can mutate anything.

我可以做一些类型级别的事情来确保这些功能只能从State中读取 ,而从不写入吗?

Is there some type-level thing that I can do to ensure that these functions can only read from the State, and never write to it?

当前情况:

iWriteData :: Int -> State MyState ()
iWriteData n = do 
    state <- get
    put (doSomething n state)

-- Ideally this type would show that the state can't change.
iReadData :: State MyState Int
iReadData = do 
    state <- get
    return (getPieceOf state)

bigFunction :: State MyState ()
bigFunction = do
    iWriteData 5
    iWriteData 10
    num <- iReadData  -- How do we know that the state wasn't modified?
    iWRiteData num

理想情况下,iReadData的类型可能为Reader MyState Int,但是与State配合使用时效果不佳.将iReadData用作常规函数似乎是最好的选择,但是随后我必须经历一次明确的提取,即在每次使用它时将状态传递给体操.我有什么选择?

Ideally iReadData would probably have the type Reader MyState Int, but then it doesn't play nicely with the State. Having iReadData be a regular function seems to be the best bet, but then I have to go through the gymnastics of explicitly extracting and passing it the state every time it's used. What are my options?

推荐答案

Reader monad注入到State中并不难:

It's not hard to inject the Reader monad into State:

read :: Reader s a -> State s a
read a = gets (runReader a)

那你可以说

iReadData :: Reader MyState Int
iReadData = do
    state <- ask
    return (getPieceOf state)

并命名为

x <- read $ iReadData

这将使您可以将Reader构建为较大的只读子程序,并将它们注入到State中,仅在需要将其与mutator组合的情况下使用.

this would allow you to build up Readers into larger read-only sub-programs and inject them into State only where you need to combine them with mutators.

不难将其扩展到monad变压器堆栈顶部的ReaderTStateT(实际上,上面的定义完全适用于这种情况,只需更改类型).将其扩展到堆栈中间的ReaderTStateT更加困难.您基本上需要一个功能

It's not hard to extend this to a ReaderT and StateT at the top of your monad transformer stack (in fact, the definition above works exactly for this case, just change the type). Extending it to a ReaderT and StateT in the middle of the stack is harder. You basically need a function

lift1 :: (forall a. m0 a -> m1 a) -> t m0 a -> t m1 a

ReaderT/StateT上方堆栈中的每个monad变压器t,这不是标准库的一部分.

for every monad transformer t in the stack above the ReaderT/StateT, which isn't part of the standard library.

这篇关于使Haskell中的一个州具有只读功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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