如何在Clojure中定义一个函数并在其中引用另一个函数?

15

我写了一个函数来计算两个集合的对称差(在4clojure网站上的一个问题)。该函数通过了单元测试,但我觉得它不够简洁,因为我有重复的代码。

(fn [x y] (set (concat 
  (keep-indexed #(if (nil? (get y %2)) %2) x)
  (keep-indexed #(if (nil? (get x %2)) %2) y))))

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

(fn [x y] (set (concat (diff x y) (diff y x))))

在哪里定义了 diff 函数并且被“inline”引用,但我不知道如何在一个函数块中完成这个操作。


2
一旦你完成了问题,你实际上可以在4clojure上看到其他人的答案,这应该能让你了解如何整理自己的尝试。 - Adrian Mouat
2个回答

23

使用letletfn

(fn [x y]
  (let [diff (... function body here ...)]
   (set
    (concat (diff x y) (diff y x)))))

11

Clojure是一种lisp语言(以及一种函数式语言),其中一个特征是函数是一等公民,在Clojure中它们被看作对象。当你使用(defn name [arg] ...)创建一个函数时,它会构建该函数并将其存储在var中,因此您可以从程序的任何地方找到它。它有点像这样:

(def name (fn [arg] ...))

现在,名为 name 的函数是广泛可用的。函数不必存储在变量中,特别是如果它们仅在函数内部需要使用。在这种情况下,将函数绑定到本地名称更加合理,正如 Matt Fenwick 的答案所示。

(let [name (fn [agr] ...)] ...)

letfn宏可以使这个过程更加优雅。重要的是要理解函数是存储在物件中的对象,你可以选择适合自己需求的容器。


3
你为什么说“重要的是要理解函数是存储在东西中的对象”?使用“对象”可能会让人们认为你在谈论面向对象的对象。在这里使用小写字母的“object”可能更好。(我知道Clojure是在JVM上实现的,许多东西都作为OO类和对象来实现,但我不认为新的Clojurians需要考虑实现细节。) - David J.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接