我是haskell的新手,我必须编写一个上下文感知的程序,所以我认为我可以使用Reader Monad来保持从文件中读取上下文,我知道如何读取文件在像[([Char],[Char])]之类的元组列表中的内容,但是我不知道如何实现Reader Monad,使得我的程序的所有组件无需使用强制风格就可以使用环境,特别是我不知道如何设置和使用环境,据我了解,我应该把它作为所有需要使用runReader函数env的环境的函数的参数,但是我很困惑,有人可以给我一些指示或者一个好东西教程?在此先感谢帮助阅读器monad
回答
我认为这是最简单的,如果你看看你如何解决这个问题,而不使用Reader,然后比较翻译版本。下面是我正在处理的一个程序中的一个缩减示例,其中环境是一组用于更新显示的回调函数。它稍微复杂一点,因为它使用ReaderT而不是Reader,但一切的工作方式基本相同。
runProcess :: Env -> State -> Action -> IO State
runProcess env state action = do
newstate <- processAction state action
let ufunc = mainUFunc env -- get the callback to update the display
ufunc newstate -- update the display
return newstate
现在我将更改它以使用Reader monad来传递环境。由于代码已经在IO中,因此有必要使用monad变换器版本ReaderT
。
runProcessR :: State -> Action -> ReaderT Env IO State
runProcessR state action = do
newstate <- lift $ processAction state action
env <- ask -- get the environment from the reader
liftIO $ (mainUFunc env) newstate -- updating is in IO; it needs to be lifted
return newstate
在这一点上,程序的主循环将主要是:
loop :: State -> ReaderT Env IO()
loop = do
action <- liftIO getAction
if action == EndLoop
then return()
else do
st' <- processActionR st action
loop st'
mainLoop :: IO()
mainLoop = do
env <- setUpCallbacks
let st = initState
runReaderT $ loop st
所以这就是你如何使用阅读器。每个使用环境参数的功能都不再需要。不采取环境的功能可以直接使用,或者如果它们是单一的,可以使用。
使用任何“正常”monad的基本方案[0]几乎是相同的全面。本质:
- 写函数返回一元类型的值,使用
do
符号,如果你喜欢,就像你写的IO
功能像main
。 - 使用您正在使用的monad的任何特定功能。
- 呼叫相互这些功能,使用标准的规则:“内部”,引起了其他值
- 绑定使用
<-
从相同单子的值来获得的价值是“跑” 。 - 使用
let
绑定任何其他值,使其独立于monadic结构。
- 绑定使用
- 使用特定monad的专门“运行”函数来评估单子计算并获得最终结果。
这样做,并且monad描述的额外功能(在这种情况下,传递一个额外的环境参数)附加功能的所有细节都会自动处理。
现在,一般的阅读器操作ask
和local
:
ask
是一个单子值保持环境;在do
块中,您可以像使用getLine
那样在IO
monad中使用相同的方法来使用它。local
提供了一个函数,它在Reader monad中提供一个新的环境和一个计算,在前者修改的环境中运行后者,然后将结果放入当前函数中。换句话说,它使用本地修改的环境运行子计算。
“运行”功能是创造性地命名runReader
,它只是发生在读者单子和环境价值的计算,使用后者运行前,并返回单子之外的最终结果。
作为一个例子,这里的一些功能的读者单子,那里的环境是说,当停止“最大值”做一些无意义的计算:
import Control.Monad.Reader
computeUpToMax :: (Int -> Int) -> Int -> Reader Int [Maybe Int]
computeUpToMax f x = do
maxVal <- ask
let y = f x
if y > maxVal
then return []
else do zs <- local (subtract y) (computeUpToMax f y)
z <- frob y
return (z:zs)
frob :: Int -> Reader Int (Maybe Int)
frob y = do
maxVal <- ask
let z = maxVal - y
if z == y
then return Nothing
else return $ Just z
要运行它,你会使用像这样:
> runReader (computeUpToMax (+ 1) 0) 9
[Just 8, Just 6, Nothing]
...其中9
是初始环境。
几乎完全一样的结构可以与其他单子一起使用,如State
,Maybe
或[]
,虽然在后两种情况下,你通常只需要使用一元的最终结果值,而不是使用“运行”功能。
[0]:凡正常意味着不涉及编译器魔术,最明显的“异常”monad当然是IO
。
“'=”绑定在哪里起作用? – CMCDragonkai 2014-09-04 07:45:05
@CMCDragonkai:它用于翻译'do'块。像'x < - foo'这样的行变成了一个绑定'foo >> = \ x - >',其中lambda的主体是'do'块剩余部分的(翻译后的版本)。 – 2014-09-04 14:39:23
这是恕我直言的最佳单子资源 - All About Monads,以下是Reader monad的一部分。
- 1. 点阅读器monad scala
- 2. 了解阅读器monad
- 3. CakePHP帮助阅读()
- 4. 互相帮助建立PDF阅读器?
- 5. 需要帮助,阅读一些C#
- 6. 阅读价值 - 帮助编写逻辑
- 7. 需要帮助的阅读callgrind输出
- 8. 请求帮助阅读一行JS
- 9. 帮助阅读与PHP邮件消息
- 10. 需要java applet来帮助测试屏幕阅读器
- 11. 在RSS阅读器中需要内存泄漏帮助
- 12. Monad阅读器和部分应用功能
- 13. 需要帮助在短信读卡器
- 14. BlackBerry阅读器中的qr阅读器
- 15. 阅读器vs缓冲阅读器
- 16. 需要帮助的Java与阅读双打输入文件
- 17. 帮助阅读线断开文本文件
- 18. 赛格故障,需要帮助阅读核心转储
- 19. 与J2me阅读文件混淆。请帮助我理解
- 20. 在阅读xml文件时需要帮助
- 21. 需要帮助阅读具有书籍格式的文件
- 22. 帮助基本阅读用户输入C
- 23. 需要一点帮助阅读在Java中的JSON
- 24. 我需要帮助的形式提交,请阅读详情
- 25. 需要帮助编写和阅读C#中的XML文件#
- 26. 帮助阅读AS3中复杂的XML,E4X
- 27. 我需要帮助!从CSV阅读使用Python
- 28. 需要帮助阅读/解析TCP网络代码C++
- 29. 需要帮助阅读TXT在线数据为R
- 30. Java多线程阅读..请帮助我非常新的Java :(
你确定首先需要'Reader'吗? “让所有组件可用的环境”通常不是在Haskell中编写代码的最佳方式。你能更详细地描述你正在处理的任务吗? – 2010-08-10 19:50:28
@Travis Brown:如果您拥有大量本质上静态的数据,那么在整个程序中的许多地方都需要它,这只有在运行时才可用,例如通过加载数据文件。例如,想象一个程序,其中所有文本都是在程序启动时从资源文件本地化和加载的。 – 2010-08-10 20:34:53
事实上,如果有什么听起来可疑的话,那就是'[([Char],[Char])]''的类型。知道它是一个环境,它听起来像一个字符串字典,它应该至少成为一个'Data.Map.Map字符串字符串',而不是像一个可爱的[字符串字符串字符串](http: //hackage.haskell.org/package/bytestring-trie)。 – 2010-08-10 20:37:12