2015-09-23 27 views
11

Ho letto molti articoli sul currying, ma quasi tutti sono fuorvianti, spiegando il currying come un'applicazione di funzione parziale e tutti gli esempi in genere riguardano funzioni con arity di 2, come la funzione add o qualcosa del genere.Quali sono i casi di utilizzo reale del curry?

molti anche implementazioni di curry funzione in JavaScript rende ad accettare più di 1 argomento per domanda parziale (vedi lodash), quando Wikipedia article dice chiaramente che currying è di:

tradurre la valutazione di una funzione che prende più argomenti (o una tupla di argomenti) nella valutazione di una sequenza di funzioni, ciascuna con un singolo argomento (applicazione parziale)

Quindi in pratica è una serie di applicazioni parziali ognuna con una singola rgument. E voglio davvero conoscerne gli usi reali, in qualsiasi lingua.

+0

Cosa ti fa pensare che questi altri usi del termine siano "sbagliati"? – dfeuer

risposta

7

L'uso reale del currying è un'applicazione parziale.

Il processo di per sé non è molto interessante. La cosa interessante è che il tuo linguaggio di programmazione supporti il ​​currying di default, come nel caso di F # o Haskell.

È possibile definire le funzioni di ordine superiore per il currying e l'applicazione parziale in qualsiasi linguaggio che supporti le funzioni di prima classe, ma è ben lontano dalla flessibilità che si ottiene quando ogni funzione viene curata e quindi parzialmente applicabile senza dover Fai qualcosa.

Quindi, se si vedono persone che confondono curry e applicazione parziale, è a causa di quanto strettamente questi concetti sono legati lì - dal momento che il curring è onnipresente, non si ha realmente bisogno di altre forme di applicazione parziale rispetto all'applicazione di funzioni curry a argomenti consecutivi.

+3

Come qualcuno che è stato nella posizione di OP e di recente sono venuto a vedere il fascino del currying, non potrei essere più d'accordo con questa risposta. Dopo aver letto https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch4.html e http://ramdajs.com/0.17/docs/#curry, le cose hanno senso! Si tratta di avere ogni funzione al curry di default, che apre la porta all'utilizzo di funzioni parzialmente applicate come "blocchi" nel codice. – TW80000

4

È utile passare il contesto.

Considerare la funzione 'mappa'. Ci vuole una funzione come argomento:

map : (a -> b) -> [a] -> [b] 

Data una funzione che utilizza una forma di contesto:

f : SomeContext -> a -> b 

Ciò significa che è possibile utilizzare la funzione elegantemente mappa senza dover indicare il 'a'-argomento :

map (f actualContext) [1,2,3] 

Senza strigliare, si dovrà utilizzare un lambda:

map (\a -> f actualContext a) [1,2,3] 

Note:

map è una funzione che prende una lista contenente i valori di a, una funzione f. Costruisce un nuovo elenco prendendo ciascuno a e applicando f a esso, risultante in un elenco di b

ad es. map (+1) [1,2,3] = [2,3,4]

1

È possibile suddividere il codice di riferimento sul codice in due gruppi di problemi (io uso Haskell per illustrare). Sintattico, implementazione.

Sintassi Problema 1:

Currying permette una maggiore chiarezza codice in taluni casi. Cosa significa chiarezza? La lettura della funzione fornisce una chiara indicazione della sua funzionalità. ad es. La funzione mappa

map : (a -> b) -> ([a] -> [b]) 

Leggi in questo modo, si vede che la mappa è una funzione di ordine superiore che solleva una funzione trasformando as-bs a una funzione che trasforma [a]-[b].

Questa intuizione è particolarmente utile quando si comprendono tali espressioni.

map (map (+1)) 

La mappa interna ha tipo sopra [a] -> [b]. Per capire il tipo di mappa esterna, applichiamo ricorsivamente la nostra intuizione dall'alto. La mappa esterna solleva quindi [a] -> [b] in [[a]] -> [[b]].

Questa intuizione ti porterà avanti MOLTO. Una volta generalizzato map su fmap, un map su contenitori arbitrari, diventa davvero facile leggere espressioni come tali (Nota ho monomorfizzato il tipo di ogni fmap in un tipo diverso per il gusto dell'esempio).

showInt : Int -> String 
(fmap . fmap . fmap) showInt : Tree (Set [Int]) -> Tree (Set [String]) 

Eventualmente quanto sopra illustra che fmap fornisce questa nozione generalizzata di sollevamento funzioni vaniglia in funzioni sopra alcuni container arbitrario.

Sintassi Problema 2:

Currying ci permette anche di esprimere le funzioni in forma libera-punto.

nthSmallest : Int -> [Int] -> Maybe Int 
nthSmallest n = safeHead . drop n . sort 

safeHead (x:_) = Just x 
safeHead _  = Nothing 

Il buon stile di cui sopra è di solito considerato come illustra pensare in termini di una pipeline di funzioni, piuttosto che la manipolazione dei dati esplicito.

Attuazione:

In Haskell, stile libero punto (attraverso accattivarsi) ci può aiutare a ottimizzare le funzioni. Scrivere una funzione in forma libera punto ci permetterà di memorizzarlo.

memoized_fib :: Int -> Integer 
memoized_fib = (map fib [0 ..] !!) 
    where fib 0 = 0 
      fib 1 = 1 
      fib n = memoized_fib (n-2) + memoized_fib (n-1) 


not_memoized_fib :: Int -> Integer 
not_memoized_fib x = map fib [0 ..] !! x 
    where fib 0 = 0 
      fib 1 = 1 
      fib n = not_memoized_fib (n-2) + not_memoized_fib (n-1) 

scrittura come una funzione curry come nella versione memoized per trattamento funzione curry come entità e quindi memoizes esso.

Problemi correlati