簡體   English   中英

Clojure中是否有標准的參數序列同一性函數?

[英]Is there a standard argument sequence identity function in Clojure?

Clojure標准庫中是否有一個等效於以下功能的函數?

(fn [& args] args)

如果沒有,為什么?

用法示例:

(take 10 (apply (fn [& args] args) (range)))
;=> (0 1 2 3 4 5 6 7 8 9)

;; ironically, map isn't lazy enough, so let's take it up to 11
(defn lazy-map [f & colls]
  (lazy-seq (cons (apply f (map first colls))
                  (apply lazy-map f (map rest colls)))))

(defn transpose [m]
  (apply lazy-map (fn [& args] args) m))

(defn take-2d [rows cols coll]
  (take rows (map (partial take cols) coll)))

(take-2d 3 3 (transpose (map (partial iterate inc) (range))))
;=> ((0 1 2) (1 2 3) (2 3 4))

請注意,我並沒有要求使用vectorlist這樣的變換性,熱切的功能。

沒有這樣的功能,您可以隨意實現和使用它:

(defn args [& args] args)

(set (map type (apply map args [[1 2 3][4 5 6][7 8 9]])))
=> #{clojure.lang.ArraySeq}

為什么它不可用?

這是很少見卓有成效的問題:不僅我們不知道在實現者的心態發生了什么,這是行不通的,要求他們證明或文檔為什么他們沒有做什么。 是否曾考慮添加此功能? 我們怎么知道 真的有原因嗎,還是只是發生了?

另一方面,我同意args感覺更簡單,因為它繞過了已經存在的不可變序列。 我也可以理解,如果您認為僅出於禮節考慮, 不首先將參數轉換為持久性列表會更好。

但是,這不是它是如何實現的,以及使用的開銷list (和真的是可以忽略不計的專門從實例建立時ArraySeq )。 您應該對接口進行編碼,並且永遠不要掩蓋,從這個角度來看,即使listargs不會返回相同的結果,它們也是等效的

您添加了關於懶惰的評論,這是對的:如果您需要從可變參數函數中獲取參數並將其傳遞給對序列進行操作的函數,帶有list的版本將使用所有給定的參數,而args則不會。 在某些情況下,就像(apply list (range)) ,您在字面上傳遞了無數個參數,這可能會永遠掛起。

從這個角度來看,小的args函數實際上很有趣:您可以從參數移到實際序列,而不會引入潛在的問題。 但是,我不確定這種情況在實踐中多久發生一次。 實際上,我很難找到一個用例,其中就args而言,參數列表中的惰性確實很重要。 畢竟,為了傳遞無限序列,唯一的方法(?)是使用apply:

(apply f (infinite))

為了為args提供用例,這意味着我們要從參數列表轉換回單個列表,以便另一個函數g可以將其用作序列,如下所示:

(g (apply args (infinite)))

但是在那種情況下,我們可以直接調用:

(g (infinite))

在您的示例中, g代表lazy-map內的cons ,但是由於f是在輸入中給出的,因此我們無法直接編寫(cons (map ...) ...) 因此,該示例看起來像是args的真實用例,但是您應該大量記錄該功能,因為給出的代碼段非常復雜。 我傾向於認為給函數提供無限數量的參數是一種代碼味道:每個具有[& args]簽名的函數都應避免使用所有參數,因為給定的序列實際上可能像lazy-map一樣是無限的? 我想讓一個參數作為這種用法的懶惰序列(並在需要時傳遞identity ),而不是整個參數列表,以闡明意圖。 但是最后,我也不強烈反對使用args

綜上所述,除非您設法說服Rich Hickey將args作為核心函數添加,否則我相信幾乎沒有人會希望依賴於這樣做的外部庫1 :它不熟悉,但實現起來卻很瑣碎,而且大多數情況下無用。 唯一的收獲就是知道您跳過了一些轉換步驟,在大多數情況下,該步驟不會花費任何費用。 同樣,不必擔心必須在向量和列表之間進行選擇:它實際上對代碼沒有影響,並且如果可以證明有必要的話,您仍然可以稍后修改代碼。 關於懶惰,盡管我同意將參數包裝在列表或向量中對於無限制的參數列表可能會出現問題,但我不確定問題實際上是否會在實際中出現。


1 當然,如果它到達clojure.core ,每個人都會很快地說這是最有用的操作,並且絕對是慣用的</ cynic>

identity功能。 它接受一個參數,然后返回該參數。 Clojure的identity不過是單身。

用法:

(identity 4) ;=> 4

(identity [1 2 3 4]) ;=> [1 2 3 4]

我認為使用具有可變Arity的identity函數沒有多大意義,因為Clojure函數僅返回一個值。 如果要從一個函數返回多個值,則可以將它們包裝在一個seq中,以便以后進行分解。 在這種情況下,您可以擁有以下內容:

(defn varity-identity [& args]
    (map identity args))

(varity-identity 1 2 3 4 5) ;=> (1 2 3 4 5)

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM