您的问题是评估和执行之间的区别。
当你写这样的东西时:
Console.log "foo"
与您的直觉相反,这实际上并没有向控制台打印任何内容。相反,这会创建一个“动作”,该动作必须在稍后的某个时间点“执行”,然后才会将某些内容打印到控制台。
相反,同一个动作实际上可以“执行”多次,从而产生多种效果:
printFoo = Console.log "foo"
-- ^ Nothing is printed at this point
main = do
printFoo
printFoo
printFoo
-- ^ "foo" is printed three times
- “评价”正在创造“行动”
- “执行”正在运行“动作”以产生它产生的任何效果
在上面的示例中,评估发生一次,但执行 - 三次。
工作方式unless
,它接受一个Boolean
值和一个“动作”,并返回另一个“动作”:
dontPrintFoo = unless true printFoo
当您执行动作dontPrintFoo
时,它将是由返回的动作unless
,它将检查Boolean
参数并选择不执行动作printFoo
。
但是假设你有一个更复杂的场景:
dontPrintFoo = unless true $ if qux then printFoo else printBar
在这里, 的两个参数unless
在传递给unless
. 这意味着在调用之前计算/的值qux
和结果。但是结果动作将在稍后执行,当整个结果从.if
then
unless
main
但是trace
很特别。魔法。即使它产生效果(打印到控制台),编译器仍认为它是一个纯函数。喜欢2 + 3
或喜欢if qux then foo else bar
。这样做是为了方便调试:以便您可以在纯的、无效的代码中插入跟踪。
这意味着trace
在“评估”时评估,而不是“执行”。这意味着它甚至在被调用之前 unless
就被评估过,因此无论Boolean
参数是true
or ,它都会被评估false
。
如果您希望跟踪仅在unless
决定执行操作时起作用,请尝试traceM
:
unless (...) do
traceM (show scrollDelta)
foo
bar