以下是在Clojure中编写函数的两种方法:
(defn foo [a b] (+ a b))
(fn foo [a b] (+ a b))
Run Code Online (Sandbox Code Playgroud)
我可以这样称呼它们:
在'defn'的情况下
(foo 1 2)
Run Code Online (Sandbox Code Playgroud)
在'fn'的情况下
((fn foo [a b] (+ a b)) 1 2)
Run Code Online (Sandbox Code Playgroud)
'fn'似乎没有将其可选名称插入当前范围,其中'defn'似乎就是这样做的.有两种创建函数的方法还有其他差异或原因吗?有没有理由我们不像这样使用'fn':
(fn foo [a b] (+ a b))
(foo 1 2)
Run Code Online (Sandbox Code Playgroud)
Car*_*ate 15
defn被基本上定义为*:
(defmacro defn [name args & body]
`(def ~name (fn ~args ~@body)))
Run Code Online (Sandbox Code Playgroud)
或者换句话说,你基本上可以写:
(defn my-func [a]
(stuff a))
Run Code Online (Sandbox Code Playgroud)
如*:
(def my-func
(fn [a] (stuff a)))
Run Code Online (Sandbox Code Playgroud)
使用just只fn创建一个匿名函数,它不会在外部绑定任何符号.它必须使用let或def在其自身之外引用.
通过具有defn在来定义def和fn的函数,结合到符号responsibilies(以及所有随之而来的其他复杂)和处理功能行为可以被分离.
当您为其提供名称时fn,它不能在函数外部引用,但它可以用于引用自身来创建递归匿名函数:
(fn my-func [n] (my-func (inc n))
Run Code Online (Sandbox Code Playgroud)
并且,它为函数提供了一个稍微好一点的名称,以便在堆栈跟踪中显示以简化调试:
(defn my-func []
((fn my-inner-func [] (/ 1 0))))
=> #'digital-rain.core/my-func
(my-func)
java.lang.ArithmeticException: Divide by zero
at clojure.lang.Numbers.divide(Numbers.java:158)
at clojure.lang.Numbers.divide(Numbers.java:3808)
at digital_rain.core$my_func$my_inner_func__2320.invoke(form-init1838550899342340522.clj:2)
at digital_rain.core$my_func.invokeStatic(form-init1838550899342340522.clj:2)
at digital_rain.core$my_func.invoke(form-init1838550899342340522.clj:1)
Run Code Online (Sandbox Code Playgroud)
*这些都是粗略的轻描淡写,有点误导,但它们简化了事情.实际上,defn没有定义使用defmacro; defmacro实际上定义使用defn.defn还添加了一些好东西,如前/后条件检查,文档和其他元信息; 但这并不重要.我建议查看其来源以获得更深入的外观; 虽然它很复杂.clojure.core包围你的头脑的基本内容可能有点令人生畏.
| 归档时间: |
|
| 查看次数: |
1435 次 |
| 最近记录: |