【问题标题】:Why don't I get output from Debug.log in an infinite loop in the Elm REPL?为什么我不能在 Elm REPL 的无限循环中从 Debug.log 获得输出?
【发布时间】:2017-01-24 20:48:23
【问题描述】:

我正在调试一些带有无限循环的代码,但这很困难,因为我无法输出任何日志消息。这是一个简化的案例:

import Debug exposing (log)

f x =
    let _ = log "Hello, world!" ()
    in f x

如果我像 f () 这样在 Elm REPL 上运行它,它会无限循环并且永远不会像我期望的那样打印出 "Hello, world!"

我查看了Debug.log 的实现(跟随它到Native.Debug.log),但它似乎只是同步调用process.stdout.writeconsole.log,所以我很惊讶我没有看到任何输出.

【问题讨论】:

  • 我不知道 Elm 是否进行了优化传递,但如果是这样,为被忽略的绑定赋值可能会被优化掉。您是否尝试过此操作而不将日志值分配给 _
  • 好吧,它不会在非无限递归的情况下优化它:f x = let _ = log "Hello, world!" () in 5 然后调用f () 会打印Hello, world!
  • @w.brian 正确的编译器只会优化掉未使用的表达式,前提是它可以证明它没有副作用。将let _ = side_effecting_expression in foo 优化为foo 将是一个非常不正确的优化。 PS:let _ = ... 实际上并没有引入绑定。
  • @sepp2k 就编译器所知,log 是一个纯函数,将其优化掉是正确的。它不纯的事实对编译器是隐藏的,并且文档非常清楚地指出,出于这个原因,它不应该在生产中使用。

标签: elm


【解决方案1】:

这只是 Elm REPL 中的一个错误。

问题

我深入研究了 Elm REPL 的实现。相关功能在这里:Eval.Code.run

这个run 函数似乎是执行一段代码的函数。看起来每一行代码都是通过 Elm.Utils 在子进程中执行的。展开运行。它的运行方式有两个问题:

  • 子进程的标准输出没有流式传输;只有在整个子流程完成后才会返回。因此,只要您在等待代码完成评估,您就什么也看不到。
  • 如果您按 ctrl-c 过早地结束评估(效果很好,并返回到 Elm 提示符),Elm Repl 将忽略返回给它的标准输出。注意pattern match for CommandFailed

Left (Utils.CommandFailed _out err) -> throwError err

Utils.CommandFailed 结果有助于包含标准输出(绑定到_out),但此代码忽略它并抛出错误。

所以基本上这并不是 Elm 编译器或运行时发生的任何奇怪的事情,只是 REPL 在记录结果方面不如它可能的那么好。

解决方法

作为一种解决方法,为了调试无限循环之类的东西,您可以

  1. 将一些测试代码放入新文件Scratch.elm,如x = f ()
  2. elm-make Scratch.elm --output scratch.js编译代码
  3. 使用node scratch.js运行代码

然后输出将被流式传输到您的终端。

【讨论】:

  • 这是一个非常聪明的解决方法;因为 node.js 基于 v8,它是在 chrome web 浏览器中执行 javascript 的。使用node-jsdom 可以伪造一些浏览器内容
  • Elm-REPL 也使用 node.js 进行评估,因此它与 Elm REPL 运行代码的方式相同。
猜你喜欢
  • 1970-01-01
  • 2015-12-23
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多