7

Sto leggendo un libro su Clojure, e mi è venuto da un esempio che I dont comprendere appieno ..clojure chiarimento parziale

Ecco il codice in 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) 

La mia domanda è: perché è necessario il partial qui, e come si inserisce nella definizione partial, e & definizione &. Parziale ...

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. 

Quindi, come si inserisce?

risposta

6

partial in realtà non controlla quali sono le aritmetiche supportate dal primo argomento; una docstring discutibilmente più accurata direbbe che "prende una funzione f e alcuni argomenti in f". (Chiaramente se fornisci troppi argomenti, la funzione parzialmente applicata risultante verrà interrotta, anche se ciò sarà osservabile solo quando proverai a chiamarlo.) Ecco perché (partial rand-int 10) è ok anche se il numero di argomenti a rand-int fornito non è " meno del normale ".

Il motivo per cui è necessario sia partial o qualcosa di simile #(rand-int 10) qui è che repeatedly aspetta il suo argomento finale sia una funzione che si può chiamare più volte, mentre (rand-int 10) sarebbe un numero.

Confrontare questo con repeat che restituisce una sequenza con l'elemento fornito ripetuto il numero specificato di volte (o infinitamente più volte nel caso unario).Qui (rand-int 10) sarebbe un secondo argomento appropriato, ma ovviamente sarebbe un numero particolare, quindi il risultato sarebbe simile a (8 8 8 8 8 ...); repeatedly effettuerà una chiamata separata a (partial rand-int 10) per ciascun elemento della sequenza restituita, in modo da ottenere una sequenza di numeri casuali (probabilmente diversi, indipendenti).

+0

Ho pensato che in qualche modo, il problema riguardasse '(rand-int 10)' restituendo un numero .. '#()' sicuramente sembra una soluzione migliore, semanticamente –

10

Parziale è solo un modo più semplice di definire una funzione anonima che corregge alcuni degli argomenti di una funzione e quindi passa il resto dagli argomenti alla funzione creata.

In questo caso

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

è equivalente a:

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

parziale è improprio qui perché partial viene utilizzato per fissare in anticipo tutti gli argomenti (o meglio l'unico) di rand-int.

un uso più intersting di parziale illustra la sua funzione meglio:

(partial + 4) 

produce l'equivalente di:

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

(esso non letteralmente produce questo) L'idea è di costruire una funzione che prende gli argomenti non fissi, li combina con quelli fissi e chiama la funzione che hai passato a partial con sufficienti argomenti per funzionare correttamente.

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

Uso solo parzialmente in pratica quando il numero di argomenti è variabile. In caso contrario, ho una preferenza personale verso l'utilizzo del modulo lettore di funzioni anonimo #(...)

+0

Sì, penso che sarebbe semanticamente una soluzione più appropriata. Grazie –