【问题标题】:What is the difference between fn an defn in clojure?clojure中的fn和defn有什么区别?
【发布时间】:2018-03-09 01:35:04
【问题描述】:

以下是在 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)

【问题讨论】:

    标签: clojure


    【解决方案1】:

    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 创建一个匿名函数,它不会单独绑定到外部的任何符号。它必须使用letdef 绑定才能在其外部引用。

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

    当您为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 的基本内容可能有点令人生畏。

    【讨论】:

    • 而在 (fn foo [a b] (+ a b)) 的情况下,这仍然是匿名函数,如果需要递归调用匿名函数,可以在函数体内部使用 foo本身。
    • @BojanHorvat 是的,我想我最初是想添加一个关于这个的简介,但它没有成功。我现在补充一点。
    【解决方案2】:

    fn:定义了一个函数 obj 但没有给它命名。当您想创建匿名类时,这很好。给它一个名字,你需要使用 def:

    (def greet (fn [name] (str "Hello, " name)))
    

    另一方面,defn 定义了一个函数并为其命名:

    (defn greet [name] (str "Hello, " name))
    

    【讨论】:

      猜你喜欢
      • 2012-12-27
      • 2011-04-09
      • 2017-09-07
      • 2012-11-16
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多