gpt4 book ai didi

haskell - 如何正确强制评估 IO monad 中的纯值?

转载 作者:行者123 更新时间:2023-12-04 07:19:55 25 4
gpt4 key购买 nike

我需要在 IO 中强制评估纯值单子(monad)。我在写
C 绑定(bind)的高级接口(interface)。在较低的级别上,我说 newFile功能和freeFile功能。 newFile返回一些 id,不透明的对象
我已经在较低级别上定义了。你基本上不能做任何事情,但是
使用它来释放文件并纯粹计算与
那个文件。

所以,我有(简化):

execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path -- ‘fid’ stands for “file id”
let x = runGetter g fid
freeFile fid
return x

这是该功能的初始版本。我们需要计算 xfreeFile叫做。 (代码有效,如果我删除 freeFile 一切都很好,
但我想释放资源,你知道的。)

第一次尝试(我们将使用 seq 来“强制”评估):
execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
let x = runGetter g fid
x `seq` freeFile fid
return x

分段故障。直接进入文档
seq :

The value of seq a b is bottom if a is bottom, and otherwise equal to b. seq is usually introduced to improve performance by avoiding unneeded laziness.

A note on evaluation order: the expression seq a b does not guarantee that a will be evaluated before b. The only guarantee given by seq is that the both a and b will be evaluated before seq returns a value. In particular, this means that b may be evaluated before a. If you need to guarantee a specific order of evaluation, you must use the function pseq from the "parallel" package.



一个很好的说明,确实,我看到人们声称关于秩序的不同事情
在这种情况下的评估。 pseq 呢? ?我需要依赖吗 parallel只是因为 pseq ,嗯……可能还有其他方法。
{-# LANGUAGE BangPatterns #-}

execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
let !x = runGetter g fid
freeFile fid
return x

分段故障。出色地,
that answer在我的行不通
案子。但它建议 evaluate ,我们也来试试吧:
Control.Exception (evaluate)
Control.Monad (void)

execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
let x = runGetter g fid
void $ evaluate x
freeFile fid
return x

分段故障。也许我们应该使用 evaluate 返回的值?
Control.Exception (evaluate)
Control.Monad (void)

execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
let x = runGetter g fid
x' <- evaluate x
freeFile fid
return x'

不,坏主意。也许我们可以链接 seq :
execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
let x = runGetter g fid
x `seq` freeFile fid `seq` return x

这行得通。但这是正确的方法吗?也许它只是因为
一些不稳定的优化逻辑?我不知道。如果 seq关联到
在这种情况下,然后根据该描述留下 xfreeFilereturn x 时进行评估返回它的值。但同样,他们中的哪一个, xfreeFile先评估?因为我没有遇到段错误,所以它必须
x ,但是这个结果可靠吗?你知道如何强制评估 x之前 freeFile适本地?

最佳答案

一个可能的问题是 newFile正在做一些惰性 IO,而 runGetter是一个足够懒惰的消费者,运行 seq在其输出上并不强制所有 newFile的 IO 实际发生。这可以通过使用 deepseq 来解决。而不是 seq :

execGetter :: NFData a => FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
let x = runGetter g fid
x `deepseq` freeFile fid
return x

这将解决的另一种可能性是 runGetter声称是纯的,但实际上不是(并且是一个懒惰的生产者)。但是,如果是这种情况,正确的解决方法是不要使用 deepseq在这里,但要消除 unsafePerformIO 的使用来自 runGetter ,然后使用:
execGetter :: FilePath -> TagGetter a -> IO a
execGetter path g = do
fid <- newFile path
x <- runGetter g fid
freeFile fid
return x

然后应该可以在不进一步摆弄强制的情况下工作。

关于haskell - 如何正确强制评估 IO monad 中的纯值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33423827/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com