Clojure China

identity这个函数有什么意义?或者说有什么使用场景

#1

Returns its argument.

4clojure上的文档,但是这有什么用呢?

#2

例如计算一系列数字中每个数字出现的次数,并需要去掉 nil,可以用 identity 来过滤和分组:

(->> [1 0 1 nil 1 nil]
     (filter identity)
     (group-by identity)
     (map (fn [[x xs]] [x (count xs)]))
     (into {}))

;; {1 3, 0 1}

identity 可以用来过滤一个序列里是 nilfalse 的元素(参见 clojuredocs):

(filter identity [1 2 3 nil 4 false true 1234])

;; (1 2 3 4 true 1234)

总之需要用到 (fn [x] x) 的地方就是使用 identity 的时机。
再来一个临时拼凑的例子:

(def ^:dynamic *my-converter*)

(defn hello-world []
  (println "hello" (*my-converter* "world")))

(binding [*my-converter* (fn [x] (str "<" x ">"))]
  (hello-world))
;; hello <world>

(binding [*my-converter* identity]
  (hello-world))
;; hello world
#3

Haskell 也有, 总觉得是做证明的时候用到的.

#4

和 y = x 这个函数在数学中的地位一样。

#5

identity函数的类型是 identity :: T -> T,也即一个类型到同一个类型的转换,也即EndoFunction(自函数)
你可以理解为它把普通类型T提升到一个函数类型 T => T -> T。
这里有个很好的例子:

(sort-by identity [2 3 1 4])
;; (1 2 3 4)

(sort-by keyfn coll)中的keyfn本意是抽取集合中的项的key值来进行比较的,这里我们仅仅需要项来比较。

高阶函数(HOF)需要filter或者抽取原集合的项的类型来做其他操作的时候,那么就可以使用identity来提升普通类型到函数类型。

2赞
#6

还有一种使用情况,就是在destructure 的时候如果有些参数为空的情况,函数内又需要调用。可以通过identity 将空参转变为空函数以防止空指针。 不知道我理解的对不对

#7

学了点别的东西, 换一个角度理解就知道为什么有 identity 了. 了解一下 SKI 组合子:

在过程式编程当中, 一个数据, 从什么变成什么, 一般是有个指令. 但是自身到自身, 没有单独搞一个指令的必要.

但是函数式编程, 从 SKI 组合子看, 其核心设计当中是没有按照指令这样思考的, 其中都是组合子, 特别是各种流程控制, 需要通过组合子相互组合的方式(到 Haskell 就是 curried functions 调用的方式), 最终拼出来. 这时候 I 也就是 identity 这个组合子, 在组合的过程当中要来表示直接返回, 就时不时会用到了. 我猜 Clojure 从 Haskell 继承, Haskell 从更早的语言继承, 最早也能到 SKI 组合子那边去.

好吧我这讲的也是虚头巴脑的…