gpt4 book ai didi

clojure - Clojure 中的 fn 和 defn 有什么区别?

转载 作者:行者123 更新时间:2023-12-03 00:26:40 24 4
gpt4 key购买 nike

以下是在 Clojure 中编写函数的两种方法:

(defn foo [a b] (+ a b))
(fn foo [a b] (+ a b))

我可以这样调用它们:

在“defn”的情况下

(foo 1 2)

以“fn”为例

((fn foo [a b] (+ a b)) 1 2)

“fn”似乎没有将其可选名称插入到当前作用域中,而“defn”似乎正是这样做的。两种创建函数的方法还有其他区别或原因吗?我们不这样使用“fn”有什么原因吗:

(fn foo [a b] (+ a b))
(foo 1 2)

最佳答案

defn基本上定义为*:

(defmacro defn [name args & body]
`(def ~name (fn ~args ~@body)))

或者换句话说,您基本上可以写:

(defn my-func [a]
(stuff a))

作为*:

(def my-func
(fn [a] (stuff a)))

仅使用 fn 创建一个匿名函数,该函数不会单独绑定(bind)到任何外部符号。它必须使用 letdef 进行绑定(bind),才能在其自身外部引用。

通过根据 deffn 定义 defn,将函数绑定(bind)到符号(以及所有随之而来的其他复杂性)和处理函数行为可以分开。

当您为 fn 提供名称时,无法在函数外部引用它,但可以使用它来引用自身以创建递归匿名函数:

(fn my-func [n] (my-func (inc n))

并且,它为函数提供了一个稍微好一点的名称,以显示在堆栈跟踪中以方便调试:

(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)
<小时/>

* 这些都是严重的轻描淡写,并且有点误导,但它们简化了事情。

实际上,defn 并不是使用 defmacro 定义的; defmacro实际上是使用defn定义的。 defn 还添加了一些好东西,例如前/后条件检查、文档和其他元信息;但这在这里并不重要。我建议查看其 source更深入地了解;虽然这很复杂。 clojure.core 的基本原理可能会让您有点难以理解。

关于clojure - Clojure 中的 fn 和 defn 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49185304/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com