【问题标题】:How can I trace code execution in Clojure?如何在 Clojure 中跟踪代码执行?
【发布时间】:2017-01-30 22:44:41
【问题描述】:

为什么要学习 Clojure,我有时需要了解函数在每一步中的作用。例如:

(defn kadane [coll]
   (let [pos+ (fn [sum x] (if (neg? sum) x (+ sum x)))
         ending-heres (reductions pos+ 0 coll)]
     (reduce max ending-heres)))

我应该在这里和那里插入println(在哪里,如何);还是有建议的工作流程/工具?

【问题讨论】:

  • 顺便说一句,自动跟踪——并在运行时用其变量的值标记 Clojure 代码——是 Light Table editor 带来的事情之一,尽管它所有的承诺都被打破了。
  • 我只是启动 IntelliJ 的调试器并放置断点。对我来说很好。

标签: debugging clojure


【解决方案1】:

这可能不是您在单个函数级别所追求的(请参阅下面 Charles Duffy 的评论),但如果您想了解在命名空间级别(或多个)正在发生的事情,你可以使用tools.trace(披露:我是贡献者):

(ns foo.core)

(defn foo [x] x)
(defn bar [x] (foo x))

(in-ns 'user) ; standard REPL namespace

(require '[clojure.tools.trace :as trace])
(trace/trace-ns 'foo.core)

(foo.core/bar 123)
TRACE t20387: (foo.core/bar 123)
TRACE t20388: | (foo.core/foo 123)
TRACE t20388: | => 123
TRACE t20387: => 123

它不会捕获内部函数等(正如 Charles 指出的那样),并且可能会被大型代码图压倒,但在探索小型代码图时,它会非常方便。

(如果感兴趣的组与命名空间不完全对齐,也可以跟踪单独选择的 Var。)

【讨论】:

  • 我自己会提出这个建议,但是当我读到这篇文章时,OP 正试图在单个函数调用中查看,不是吗?
  • (“在单个函数调用中”不仅意味着它的参数和返回值,还意味着它包含的匿名函数)。
  • @CharlesDuffy 哦,确实,我认为你是对的。然后+1 给萨伊德。谢谢!
【解决方案2】:

如果您像大多数 Clojurian 一样将 Emacs 与 CIDER 一起使用,那么您已经拥有一个内置调试器:

https://docs.cider.mx/cider/debugging/debugger.html

您最喜欢的 IDE/编辑器可能已经内置了一些东西或插件。

还有(不分先后):

我会先看看上面的内容。但是还有其他可能性:

此外,如果函数足够简单,您可以在开发时添加 defs,以便在给定时间查看函数内部的绑定。

【讨论】:

    【解决方案3】:

    Sayid 是 Clojure Conj 2016 上展示的一个工具,它直接适用于该目的,并带有一个出色的 Emacs 插件。见the talk at which it was presented

    要查看瞬态函数的内部调用,请参阅 ws-add-inner-trace-fn(之前为 ws-add-deep-trace-fn)。

    【讨论】:

    • sayid 的作者在这里。我只是想留个便条,鼓励任何尝试 sayid 的人联系(github 问题、电子邮件、推特),以解决他们遇到的任何问题或问题。谢谢
    【解决方案4】:

    为此,我经常使用spyxspy-let 等相关功能来自the Tupelo library

    (ns tst.clj.core
      (:require [tupelo.core :as t] ))
    (t/refer-tupelo)
    
    (defn kadane [coll]
       (spy-let [ pos+ (fn [sum x] (if (neg? sum) x (+ sum x)))
                  ending-heres (reductions pos+ 0 coll) ]
         (spyx (reduce max ending-heres))))
    (spyx (kadane (range 5)))
    

    将产生输出:

    pos+ => #object[tst.clj.core$kadane$pos_PLUS___21786 0x3e7de165 ...]
    ending-heres => (0 0 1 3 6 10)
    (reduce max ending-heres) => 10
    (kadane (range 5)) => 10
    

    恕我直言,很难击败简单的println 或类似的调试。随着您接近生产,日志文件也非常宝贵。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-30
      • 2012-12-15
      • 2012-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多