如何通过Clojure中的函数返回解除引用的值

时间:2016-07-31 18:53:12

标签: function clojure functional-programming

我有一个带矢量值的原子:

(def v (atom [1 2]))

我想编写一个返回这个解除引用原子的函数。也就是说,我基本上想要编写一个函数,它将返回与此相同的结果:

=> @v
[1 2]

我对此的第一次看法是这样的:

=> (let [f #(@v)]
     (println (f)))
ArityException Wrong number of args (0) passed to: PersistentVector  clojure.lang.AFn.throwArity (AFn.java:429)

但是这当然不起作用,因为解除引用的原子不是一个函数:

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

我最终得到的解决方法是:

=> (let [f #(vec @v)]
     (println (f)))
[1 2]
nil

...但肯定必须有更好的方法来做到这一点,不必假设原子的价值是矢量吗?

4 个答案:

答案 0 :(得分:2)

现有的答案都没有给出两个最简单,最简洁的解决方案,所以这里就是。作为@Stefan的stated,您需要与此函数等效的内容:

(fn [] (deref v))

但是,deref的这种用法正是@阅读器宏旨在简化的用例:

(fn [] @v)

或者,由于(deref v)是一个函数调用,您可以改为使用#()阅读器宏:

#(deref v)

这里的要点是,在这种情况下,您不能同时使用 @#() 。但这并不意味着你不能或不应该使用一个

答案 1 :(得分:1)

有时最好将#@之类的读者结构放在一边,然后再使用函数(或宏和特殊形式):

user> (def v (atom [1 2]))
#'user/v
user> (let [f (fn [] (deref v))] (f))
[1 2]

我认为,你的例子是你真正想做的非常简化的版本。如果没有,deref可能只是您正在寻找的功能。

答案 2 :(得分:1)

  

我想写一个会返回这个解除引用原子的函数

(def v (atom [1 2]))
(defn foo [] @v)
(foo) ;;=> [1 2]

答案 3 :(得分:1)

首先:出现此错误的原因,是lambda表达式糖语法的扩展。你可以这样想:

#(expression*) => (fn [] (expression*))

所以,这样思考:

#(@v) => (fn [] (@v))@v又扩展为(deref v)(很容易通过宏扩展看到),引导您进入以下形式:

(fn [] ((deref v)))

实际上你对错误的假设原因是正确的:取消引用的结果被称为函数,但事实上它可能是(因为向量具有函数语义),而它只是缺少一个强制参数(正是错误文本中的内容)。 所以它应该适用于此:#(@v 0) => (fn [] ((deref v) 0))

user> (let [f #(@v 0)]
        (println (f)))
1
nil

就个人而言,我会选择部分应用程序,而不是lambda表达式来解决这个问题:

user> (let [f (partial deref v)]
        (println (f)))
[1 2]
nil