此 JavaScript 代码的 ClojureScript 等效项

ClojureScript equivalent for this JavaScript code

我正在尝试在我的 ClojureScript 代码中使用 esrecurse,我有一个有效的 JavaScript 片段,看起来像这样

esrecurse.visit(ast, {
  Literal: console.log
});

我正在尝试为 ClojureScript 想出等价物,但每当我 运行 它 esrecurse.visit 都不会被调用

#(.visit esrecurse % (js-obj "Literal" (fn [node] node)))

其中 % 是 AST。老实说,我不确定我做错了什么,我也尝试过以不同的方式传递第二个参数,比如

#(.visit esrecurse (first (vals %)) {:Literal (fn [node] node)})

没有成功。

我正在这样调用 mutate?

(defn mutate?
  "applies a mutation to the ASTs,
  returns the mutated, or non mutated, ASTs"
  [asts]
  (map
   #(.visit esrecurse % #js {:Literal print})
   asts))

(mutate? (reader/to-ast (reader/read "./test/example-project/lib")))

但是对于这个版本和我的版本,我仍然没有得到任何东西,我也尝试传递 identity 而不是 print,但结果我只得到 (nil)

对于 esrecurse.visit.

的模拟实现,这对我来说效果很好
(defn visit [ast]
  (.visit esrecurse ast #js {:Literal print}))

(visit #js {:type "Literal"})

;; prints #js {:type "Literal"}

模拟代码:

var esrecurse = {
  visit(node, visitor) {
    visitor.Literal(node);
  }
}

这是同一想法的简化版。

 #(.visit esrecurse % #js {:Literal print}))

验证您是否正确调用了该函数,因为您的第一个实现对我来说看起来不错并且可以代替上述任一函数。

我猜,你在第二个例子中没有看到任何事情发生的原因是因为 Clojure 的序列是 惰性的——这意味着你的计算不会应用直到您要求结果。

这些惰性序列(take return 也是一个)仅在调用 doalldorundoseq 时才会被评估。

如果您调用 print 或计算在 repl 中 return 是惰性序列的表达式,就会在幕后发生这种情况。

您可以尝试使用 doall 强制计算惰性表达式。

(doall
  (mutate? (reader/to-ast (reader/read "./test/example-project/lib"))))

这感觉不自然,这就是重点。作为一种相当纯粹的函数式编程语言,Clojure 希望您主要编写没有副作用的函数。

这是 JavaScript 互操作可能会很痛苦的示例,因为 esrecurse.visit 实际上 return 不是一个值,调用 map return 一系列 nil 值。我很想拉出匿名函数并将其重新定义为始终 return 它传递的 AST。

(defn visit [ast]
  (.visit esrecurse ast #js {:Literal print})
  ast)

(defn mutate?
  "applies a mutation to the ASTs,
  returns the mutated, or non mutated, ASTs"
  [asts]
  (map visit asts))

(doall
  (mutate? (reader/to-ast (reader/read "./test/example-project/lib"))))

请注意,mutate? 是命名函数的约定,return 是一个布尔值。也许您的意思是 mutate!,这是可能执行副作用的函数的约定?