如何在Clojure中定义函数内的函数并引用该函数?

Mat*_*hew 15 clojure

我写了一个函数来计算两组的对称差异(4clojure站点上的一个问题).该函数通过了单元测试,但考虑到我有重复的代码,它并不像我想的那样干净.

(fn [x y] (set (concat 
  (keep-indexed #(if (nil? (get y %2)) %2) x)
  (keep-indexed #(if (nil? (get x %2)) %2) y))))
Run Code Online (Sandbox Code Playgroud)

显然我更喜欢这样的东西:

(fn [x y] (set (concat (diff x y) (diff y x))))
Run Code Online (Sandbox Code Playgroud)

diff函数定义并引用"inline",但我不知道如何在一个fn块中执行此操作.

Mat*_*ick 23

使用letletfn:

(fn [x y]
  (let [diff (... function body here ...)]
   (set
    (concat (diff x y) (diff y x)))))
Run Code Online (Sandbox Code Playgroud)


Art*_*ldt 11

使Clojure成为lisp(以及一般的函数式语言)的一个特性是,函数是 Clojure 中的第一类东西,特别是它们是Object.当你使用(defn name [arg] ...)if 函数构建函数然后将它存储在var中时,你可以在程序的任何地方找到它.它很像这样:

(def name (fn [arg] ...))
Run Code Online (Sandbox Code Playgroud)

now name包含一个可以广泛访问的函数.函数不必存储在变量中,特别是如果它们仅在函数中需要.在这种情况下,将函数绑定到本地名称更有意义,就像Matt Fenwick的答案一样.

(let [name (fn [agr] ...)] ...)
Run Code Online (Sandbox Code Playgroud)

letfn宏观使这更优雅.重要的是要了解功能是存储在物体中的对象,您可以选择适合您需要的容器.

  • 你为什么说“重要的部分是理解函数是存储在事物中的**对象**”?说“对象”可能会让人认为您在谈论面向对象意义上的对象。我认为小写的“对象”在这里可能会更好。(我知道 Clojure 是在 JVM 上实现的,其中很多东西都是作为 OO 类和对象实现的,但我认为新的 Clojure 人不一定需要考虑实现细节。) (3认同)