gpt4 book ai didi

haskell - monad 内的执行顺序

转载 作者:行者123 更新时间:2023-12-02 08:11:56 25 4
gpt4 key购买 nike

我正在学习如何使用 State monad,我注意到执行顺序方面有一些奇怪的行为。删除涉及使用实际状态的分散注意力的部分,假设我有以下代码:

import Control.Monad
import Control.Monad.State
import Debug.Trace

mainAction :: State Int ()
mainAction = do
traceM "Starting the main action"
forM [0..2] (\i -> do
traceM $ "i is " ++ show i
forM [0..2] (\j -> do
traceM $ "j is " ++ show j
someSubaction i j
)
)

在 ghci 中运行 runState mainAction 1 会产生以下输出:

j is 2          
j is 1
j is 0
i is 2
j is 2
j is 1
j is 0
i is 1
j is 2
j is 1
j is 0
i is 0
Outside for loop

这似乎与预期的执行顺序相反。我认为这可能是 forM 的一个怪癖,并尝试使用 sequence 进行尝试,它明确指出它从左到右按顺序运行计算,如下所示:

mainAction :: State Int ()
mainAction = do
traceM "Outside for loop"
sequence $ map handleI [0..2]
return ()
where
handleI i = do
traceM $ "i is " ++ show i
sequence $ map (handleJ i) [0..2]
handleJ i j = do
traceM $ "j is " ++ show j
someSubaction i j

但是,sequence 版本会产生相同的输出。就此处发生的执行顺序而言,实际逻辑是什么?

最佳答案

Haskell 是,这意味着事情不会立即执行。只要需要结果,事情就会被执行——但不会更早。有时,如果不需要结果,代码根本不会执行。

如果您在纯函数中添加一堆 trace 调用,您将看到这种惰性的发生。首先需要执行的事情将首先执行,因此这就是您首先看到的 trace 调用。

当有人说“计算是从左到右运行”时,它的意思是结果将与计算从左到右运行相同。实际发生的情况可能非常不同。

这实际上就是为什么在纯函数中进行 I/O 是一个坏主意。正如您所发现的,您会得到“奇怪”的结果,因为执行顺序几乎可以是产生正确结果的任何顺序。

为什么这是一个好主意?当语言不强制执行特定的执行顺序(例如命令式语言中传统的“从上到下”顺序)时,编译器可以自由地进行大量优化,例如根本不执行某些代码,因为它的不需要结果。

我建议您不要过多考虑 Haskell 中的执行顺序。应该没有理由这样做。将其留给编译器。想想你想要哪些值。该函数是否给出正确的值?然后它就可以工作,无论它以什么顺序执行。

关于haskell - monad 内的执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29732450/

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