关于懒惰的“和"子句的评估 [英] Evaluation of 'and' clause with regards to laziness
问题描述
我不明白为什么以下代码会表现出这样的行为:
I don't understand why the following code behaves the way it does:
myand :: Bool -> Bool -> Bool
myand True True = True
myand _ _ = False
containsAandB :: String -> IO Bool
containsAandB s = do
containsA <- do
putStrLn $ "Check if 'a' is in " ++ s
return $ 'a' `elem` s
containsB <- do
putStrLn $ "Check if 'b' is in " ++ s
return $ 'b' `elem` s
return $ containsA `myand` containsB
这是我测试功能时的输出:
This is the output when I test the function:
*Main> containsAandB "def"
Check if 'a' is in def
Check if 'b' in in def
False
请注意(&&)的行为类似于'myand',我只是编写了一个自定义函数以更好地可视化发生的事情.
我为'Check if 'b' is in def
部分感到惊讶,因为containsA
已经为假,因此无论containsB
为何都可以对"myand"进行求值.
Note that (&&) behaves just like 'myand', I just wrote a custom function to better visualize what's happeninig.
I'm surprised about the 'Check if 'b' is in def
part since containsA
is already false so 'myand' can be evaluated regardless of containsB
.
问题1:
为什么还要对containsB
进行评估是否有特定原因?我的理解是,除非有必要,否则不会评估containsB <- do ...
语句,但我的猜测是由于它是IO,因此行为可能有所不同,因此没有副作用吗?
Question 1:
Is there a particular reason why containsB
has to be evaluated too? My understanding was that the containsB <- do ...
statement is not evaluated unless it's required but my guess is that this might behave differently since it's IO and therefore not free of side effects?
问题2:
在不处理嵌套的if-else
子句的情况下,获得所需行为(如果containsA
为false,则不检查containsB
)的最佳实践方法是什么?
Question2:
What's the best practice approach to get the desired behavior (if containsA
is false, containsB
is not checked) without dealing with nested if-else
clauses?
推荐答案
问题1: 为什么还必须对containsB进行评估,是否有特定的原因?我的理解是,除非需要,否则不对containsB<-do ...语句进行评估,但我的猜测是,由于它是IO,因此行为可能有所不同,因此没有副作用?
Question 1: Is there a particular reason why containsB has to be evaluated too? My understanding was that the containsB <- do ... statement is not evaluated unless it's required but my guess is that this might behave differently since it's IO and therefore not free of side effects?
您的实验存在缺陷,因为您执行了IO
. IO
的重要方面之一是要遵守IO
语句的顺序.因此,即使由于懒惰,我们也不需要某个值,也会执行IO
部分.
Your experiment is flawed because you perform IO
. One of the important aspects of IO
is that the order of IO
statements is respected. So even if due to lazyness, we do not need a certain value, the IO
part is executed.
这在IO
的世界中是合乎逻辑的:假设我们读取了一个文件,并且我们分为三个部分.我们阅读了前两部分,然后阅读了第三部分.但是现在想象一下,由于懒惰,第二个IO
命令将永远不会执行.然后,这意味着第三部分实际上读取了文件的第二部分.
This is logical in the world of IO
: imagine that we read a file, and we have three parts. We read the first two parts, and then we read the third one. But now imagine that due to laziness, the second IO
command is never executed. Then that would mean that third part actually reads the second part of the file.
因此,简而言之由于IO
,对语句 进行了评估.但是只有IO
语句.因此,除非需要,否则return
内包装的值不会被 评估.支票'b' `elem` s
仅在我们需要时进行.
So in short due to IO
, the statements are evaluated. But only the IO
statements. So the value wrapped inside the return
is not evaluated, unless you need it. The check 'b' `elem` s
only happens when we need it.
但是,有一些方法可以从中"欺骗" IO
.例如,trace
(来自Debug.Trace
)模块将执行"不安全的IO ":给出评估后,它将打印错误消息.如果我们写:
There are however ways to "trick" the IO
out of this. For example trace
(from the Debug.Trace
) module will perform "unsafe IO": it will print the error message given it is evaluated. If we write:
Prelude> import Debug.Trace
Prelude Debug.Trace> myand (trace "a" False) (trace "b" False)
我们得到了:
Prelude Debug.Trace> myand (trace "a" False) (trace "b" False)
a
False
问题2: 在不处理嵌套的if-else子句的情况下,获得所需行为(如果containsA为false,不检查containsB)的最佳实践方法是什么?
Question2: What's the best practice approach to get the desired behavior (if containsA is false, containsB is not checked) without dealing with nested if-else clauses?
如前所述,正常行为是containsB
.但是,如果您执行IO
动作,则必须在实际执行检查之前执行这些 .这基本上是IO
的(>>=)
运算符(您在do
块中暗含使用此运算符)处理的方面之一.
Well as said before, normal behavior is that containsB
is not evaluated. But if you perform IO
actions, those have to be performed before you actually do the checking. This is bascially one of the aspects that the (>>=)
operator for IO
(you use this operator implcitly in a do
block) handles.
这篇关于关于懒惰的“和"子句的评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!