我有一个带矢量值的原子:
(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
...但肯定必须有更好的方法来做到这一点,不必假设原子的价值是矢量吗?
答案 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