在 PureScript 中比较整数元组有什么错误?

What do I wrong comparing a tuple of integers in PureScript?

调试鼠标移动事件的事件处理程序,我编写了以下代码:

 unless (scrollDelta == Tuple 0 0) $ trace (show scrollDelta) \_ -> do ...

然后我得到控制台输出

Tuple 0 0

这背后的想法是在用户按下第一个鼠标按钮时移动鼠标时保存鼠标位置的差异。

这是编译器错误吗?

我的解决方法是将 scrollDelta 的类型更改为 Maybe (Tuple Int Int),其中 Nothing 表示“按下按钮时没有鼠标移动”,而不是 Tuple 0 0,这有效。

你的问题是评估执行之间的区别。

当你写这样的东西时:

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 值和一个“操作”,并且它 returns 另一个“操作” :

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 还是 false 都会被评估].


如果您希望跟踪仅在 unless 决定执行操作时才起作用,请尝试 traceM:

unless (...) do
    traceM (show scrollDelta)
    foo
    bar