是什么名字?”在Clojure的fn中争论?

时间:2019-06-13 19:05:32

标签: clojure

我正在阅读拉斯·奥尔森(Russ Olsen)的书《 Getting Clojure》。在第8章“ Def,Symbol和Vars”中,有以下函数定义:

(def second (fn second [x] (first (next x))))
                ^^^^^^

我的问题是关于带下划线的second,其次。

起初,我认为这种语法是错误的,因为匿名函数不需要名称。但是as it turnes out,这种语法是正确的。

Usage: (fn name? [params*] exprs*)
       (fn name? ([params*] exprs*) +)

我尝试比较以下两个函数调用。

user> (fn second [x] (first (rest x)))
#function[user/eval5642/second--5643]
user> (fn [x] (first (rest x)))
#function[user/eval5646/fn-5647]

除了函数的名称外,似乎没有什么区别。

为什么name?会有一个fn自变量?

2 个答案:

答案 0 :(得分:5)

您可以在创建多个Arity时使用它:

(fn second
      ([x] (second x 1))
      ([x y] (+ x y)))

或者如果您需要进行递归调用:

(fn second [x] (when (pos? x)
                  (println x)
                  (second (dec x))))

答案 1 :(得分:4)

主要有两种用法:

  • 递归函数(您现在知道名称)
user=> ((fn foo [x] (when (pos? x) (println x) (foo (dec x)))) 3)
3
2
1
nil

  • 更好的堆栈跟踪(名称将为您提供更好的提示,以指示发生错误的地方)
user=> (map (fn bar [x] (inc x)) ["a"])
Error printing return value (ClassCastException) at clojure.lang.Numbers/inc (Numbers.java:137).
java.lang.String cannot be cast to java.lang.Number
user=> (pst)
ClassCastException java.lang.String cannot be cast to java.lang.Number
      clojure.lang.Numbers.inc (Numbers.java:137)
      user/eval8020/bar--8021 (NO_SOURCE_FILE:1)
      clojure.core/map/fn--5866 (core.clj:2753)
      clojure.lang.LazySeq.sval (LazySeq.java:42)
      clojure.lang.LazySeq.seq (LazySeq.java:51)
      clojure.lang.RT.seq (RT.java:535)
      clojure.core/seq--5402 (core.clj:137)
      clojure.core/seq--5402 (core.clj:137)
      puget.printer.PrettyPrinter (printer.clj:529)
      puget.printer/iseq-handler--1663 (printer.clj:314)
      puget.printer/iseq-handler--1663 (printer.clj:312)
      puget.printer/format-doc* (printer.clj:223)

(请注意user/eval8020/bar--8021