2013-04-13 39 views
7

我在讀一本關於Clojure的,我來過一個例子,我不完全瞭解..Clojure的部分澄清

這裏是REPL代碼:

user=> (repeatedly 10 (rand-int 10)) 
ClassCastException java.lang.Integer cannot be cast to clojure.lang.IFn clojure.core/repeatedly/fn--4705 (core.clj:4642) 

user=> (repeatedly 10 (partial rand-int 10)) 
(5 0 5 5 2 4 8 8 0 0) 

我的問題是: 爲什麼在這裏需要partial,以及如何符合partial定義, 和repeatedly定義&語法。部分...

Takes a function f and fewer than the normal arguments to f, and 
    returns a fn that takes a variable number of additional args. When 
    called, the returned function calls f with args + additional args. 

那麼這怎麼適合?

回答

6

partial實際上並未檢查其第一個參數支持哪個arities;一個可以說是更準確的文檔字符串會說它「對f有一個函數f和一些參數」。 (很顯然,如果提供的參數太多,所產生的部分應用函數將被打破,儘管只有在您嘗試調用它時纔會被觀察到。)所以這就是爲什麼(partial rand-int 10)可以正常工作,即使提供的參數數量並非「rand-int」少於正常「。

爲什麼這裏需要或者partial或類似#(rand-int 10)的原因是repeatedly預計其最後一個參數是它可以反覆調用的函數,而(rand-int 10)將是一個數字。

將此與repeat進行比較,它返回一個序列,其中提供的項目重複指定的次數(或一次情況下的無限次數)。這裏(rand-int 10)將是一個適當的第二個參數,但當然這將是一些特定的數字,所以結果看起來像(8 8 8 8 8 ...); repeatedly將爲每個返回的序列項目分別撥打(partial rand-int 10),以便從中獲得一系列(可能是不同的,獨立的)隨機數。

+0

我想,不知何故,這個問題是關於'(rand-int 10)'返回一個數字..# '#()'絕對看起來像一個更好的解決方案,語義 –

10

部分是定義一個匿名函數的簡單方法,該函數修復某個函數的某些參數,然後將其餘參數從參數傳遞到創建的函數。

在這種情況下

user> (repeatedly 10 (partial rand-int 10)) 
(3 1 3 6 1 2 7 1 5 3) 

等同於:

user> (repeatedly 10 #(rand-int 10))       
(9 5 6 0 0 5 7 6 9 6) 

部分是這裏的用詞不當,因爲partial正在使用事先所有的參數(或者更確切地說,只有一個),以固定到蘭德-INT。

更野趣使用的部分示出了它的功能較好:

(partial + 4) 

產生的等效的:

(fn [& unfixed-args] (apply + (concat [4] unfixed-args))) 

(它不字面上產生此) 這個想法是構建一個功能將未固定的參數與固定的參數結合起來,然後使用足夠的參數調用傳遞給partial的函數以正常工作。

user> ((fn [& unfixed-args] (apply + (concat [4] unfixed-args))) 5 6 7 8 9)  
39 
user> ((partial + 4) 5 6 7 8 9) 
39 

我只在實際中使用部分參數的數量是可變的。否則,我個人偏好使用匿名函數讀取器形式#(...)

+0

是的,我認爲這將在語義上更合適的解決方案。謝謝 –