【问题标题】:Clojure functions and thread macroClojure 函数和线程宏
【发布时间】:2020-07-17 06:52:05
【问题描述】:

我是 Clojure 语言的新手。

在阅读Clojure functions 时,我找到了示例#([%])。所以我尝试如下使用它:

(def test1 #([%]))
(test1 5)

因此,我收到以下错误:

ArityException Wrong number of args (0) passed to: PersistentVector  clojure.lang.AFn.throwArity (AFn.java:429)

这似乎是它试图调用我想要返回的数组。

挖了一阵子,找到解决办法如下:

(def test1 #(-> [%]))
(test1 5)

我有一些问题:

  1. 为什么#([%]) 不起作用?我对表达式 #([x]) 做了什么?
  2. 在正确的示例中,我使用了thread-first macro。根据其文档,它用于将参数传递给下一个函数,例如(-> x (+ 1))。在这种情况下,我什至没有要传递的函数; *在这种情况下,next 函数是什么?我无法理解为什么它解决了我的问题

【问题讨论】:

  • 规范为#(vector x)。答案
  • 感谢@leetwinski,我使用这些功能只是为了学习。教程本身建议使用vector 函数。
  • stackoverflow.com/questions/4921566/… 对您的主要问题进行了非常详尽的介绍。不过,我不会将其作为重复项关闭,因为对 -> 的额外讨论很有用。

标签: clojure


【解决方案1】:

问题 1

语法#([%]) 转换为:“创建一个函数,调用该函数时将评估表达式([%])% 是传递给函数的第一个(也是唯一一个)参数”。此表达式具有函数调用的语法,[%] 是要调用的函数。您可以使用macroexpand 查看发生了什么:

(macroexpand '#([%]))
;; => (fn* [p1__6926#] ([p1__6926#]))

clojure 中的持久向量类是clojure.lang.PersistentVector。它们为 arity 1 实现了 IFn 接口,因此您可以将向量视为将索引映射到元素的函数。但是他们没有实现 arity 0,这就是你想要调用的。换句话说,您的代码不起作用:

(def test1 #([%]))
(test1 5) ;; ERROR

但是,如果您将参数 0 传递给您的函数 [%],您将取回该元素:

(def test1 #([%] 0))
(test1 5)
;; => 5

你知道会发生什么吗?但是,对于您正在尝试做的事情,有一个更好的方法:[a b c] 语法只是调用(vector a b c) 的糖。所以要得到一些有用的东西,你可以这样做

(def test1 vector)
(test1 5)
;; => [5]

问题 2

线程优先宏的语法为(-> x f0 f1 f2 ...),其中x 是初始值,f0f1 等是函数调用,它们的第一个参数被省略,替换为正在通过管道。再次我们可以使用macroexpand来理解:

(macroexpand '(-> x f0 f1 f2))
;; => (f2 (f1 (f0 x)))

但在您的情况下,函数调用被忽略了。为了分析您的第二个示例,我们需要使用 clojure.walk/macroexpand-all 进行完整扩展,因为我们有嵌套宏:

(clojure.walk/macroexpand-all '#(-> [%]))
;; => (fn* [p1__6995#] [p1__6995#])

虽然,我们也可以一步一步看:

(macroexpand '#(-> [%]))
;; => (fn* [p1__7000#] (-> [p1__7000#]))

(macroexpand '(-> [p1__7000#]))
;; => [p1__7000#]

所以回答你的问题:(-> [%]) 中没有下一个函数。 next 函数的数量可以是任何非负数,包括零,(-> [%]) 就是这种情况。

【讨论】:

    【解决方案2】:

    @Rulle 对细节进行了详尽的解释。

    我可以指出最重要的部分吗? Your reference 来自 Clojure.org 说:

    ;; DO NOT DO THIS
    #([%])
    

    所以,不要那样做!这是一个愚蠢的把戏,只会引起混乱和痛苦。你为什么要那个???

    【讨论】:

    • 感谢您的帖子。我只是在学习语言,所以我只是想尝试一下。
    猜你喜欢
    • 1970-01-01
    • 2020-05-18
    • 2011-08-09
    • 1970-01-01
    • 2012-04-21
    • 2020-05-29
    • 2011-12-12
    • 1970-01-01
    相关资源
    最近更新 更多