Che cos'è 'Currying'?


653

Ho visto riferimenti a funzioni curry in diversi articoli e blog ma non riesco a trovare una buona spiegazione (o almeno una che abbia senso!)


12
[Lasciato come commento, poiché sarà inutile per i non matematici.] Secondo la definizione di una categoria chiusa cartesiana, esiste una famiglia fissa di aggiunte (naturalmente parametrizzate da A) tra X -> X x A e X -> X ^ A. Gli isomorfismi hom (X x A, Y) <-> hom (X, Y ^ A) sono le funzioni currye uncurrydi Haskell. Ciò che è importante qui è che questi isomorfismi sono fissati in anticipo, e quindi "integrati" nella lingua.
Alexandre C.,

3
C'è un bel tutorial qui per curry in haskell learnyouahaskell.com/higher-order-functions#curried-functions brevi commenti è che add x y = x+y(curry) è diverso da add (x, y)=x+y(non fretta)
Jaider

Risposte:


872

Il curriculum è quando si scompone una funzione che accetta più argomenti in una serie di funzioni che prendono ciascuno solo un argomento. Ecco un esempio in JavaScript:

function add (a, b) {
  return a + b;
}

add(3, 4); // returns 7

Questa è una funzione che accetta due argomenti, aeb, e restituisce la loro somma. Ora curry questa funzione:

function add (a) {
  return function (b) {
    return a + b;
  }
}

Questa è una funzione che accetta un argomento, a, e restituisce una funzione che accetta un altro argomento, b, e quella funzione restituisce la loro somma.

add(3)(4);

var add3 = add(3);

add3(4);

La prima istruzione restituisce 7, come l'istruzione add (3, 4). La seconda istruzione definisce una nuova funzione chiamata add3 che aggiungerà 3 al suo argomento. Questo è ciò che alcune persone possono chiamare una chiusura. La terza istruzione utilizza l'operazione add3 per aggiungere da 3 a 4, producendo di nuovo 7 come risultato.


236
In senso pratico, come posso utilizzare questo concetto?
Fragola

43
@Strawberry, ad esempio, hai un elenco di numeri in un [1, 2, 3, 4, 5]che desideri moltiplicare per un numero arbitrario. In Haskell, posso scrivere map (* 5) [1, 2, 3, 4, 5]per moltiplicare l'intero elenco 5e quindi generare l'elenco [5, 10, 15, 20, 25].
Nyson,

62
Capisco cosa fa la funzione mappa, ma non sono sicuro di capire il punto che stai cercando di illustrare per me. Stai dicendo che la funzione mappa rappresenta il concetto di curry?
Fragola,

78
@Strawberry Il primo argomento mapdeve essere una funzione che accetta solo 1 argomento - un elemento dall'elenco. La moltiplicazione - come concetto matematico - è un'operazione binaria; ci vogliono 2 argomenti. Tuttavia, in Haskell *c'è una funzione curry, simile alla seconda versione di addquesta risposta. Il risultato di (* 5)è una funzione che accetta un singolo argomento e lo moltiplica per 5 e che ci consente di usarlo con la mappa.
Doval,

26
@Strawberry La cosa bella dei linguaggi funzionali come Standard ML o Haskell è che puoi ottenere curry "gratis". Puoi definire una funzione multi-argomento come faresti in qualsiasi altra lingua, e ne otterrai automaticamente una versione al curry, senza dover aggiungere tu stesso un sacco di lambda. In questo modo è possibile produrre nuove funzioni che accettano meno argomenti da qualsiasi funzione esistente senza troppi problemi e che facilitano il passaggio ad altre funzioni.
Doval,

125

In un'algebra di funzioni, trattare con funzioni che accettano più argomenti (o un argomento equivalente che è una N-tupla) è in qualche modo inelegante - ma, come ha dimostrato Moses Schönfinkel (e, indipendentemente, Haskell Curry), non è necessario: tutto necessità sono funzioni che accettano un argomento.

Quindi, come gestisci qualcosa che esprimeresti naturalmente come, diciamo f(x,y),? Bene, lo consideri equivalente a f(x)(y)- f(x), chiamalo g, è una funzione e applichi quella funzione a y. In altre parole, hai solo funzioni che accettano un argomento - ma alcune di quelle funzioni restituiscono altre funzioni (che accettano ANCHE un argomento ;-).

Come al solito, Wikipedia ha una bella voce di riepilogo su questo, con molti suggerimenti utili (probabilmente inclusi quelli riguardanti le tue lingue preferite ;-) e un trattamento matematico leggermente più rigoroso.


1
Suppongo un commento simile al mio sopra - non ho visto che i linguaggi funzionali limitano le funzioni a prendere un singolo argomento. Mi sbaglio?
Eric M,

1
@hoohoo: i linguaggi funzionali generalmente non limitano le funzioni a un singolo argomento. Tuttavia, a un livello più basso, più matematico, è molto più facile gestire funzioni che accettano solo un argomento. (Nel calcolo lambda, ad esempio, le funzioni accettano solo un argomento alla volta.)
Sam DeFabbia-Kane,

1
OK. Un'altra domanda allora. La seguente è una vera affermazione? Il calcolo lambda può essere utilizzato come modello di programmazione funzionale ma la programmazione funzionale non è necessariamente applicata al calcolo lambda.
Eric M,

7
Come notano le pagine di Wikipedia, la maggior parte dei linguaggi FP "abbelliscono" o "aumentano" il calcolo lambda (ad esempio con alcune costanti e tipi di dati) piuttosto che semplicemente "applicarlo", ma non è così vicino. A proposito, cosa ti dà l'impressione che, ad esempio, Haskell NON "limiti le funzioni a prendere un singolo argomento"? Lo fa sicuramente, anche se questo è irrilevante grazie al curry; ad esempio div :: Integral a => a -> a -> a, noti quelle frecce multiple? "Mappa a per mappare una a a" è una lettura ;-). Si potrebbe utilizzare una (sola) argomento tupla per div& C, ma che sarebbe davvero anti-idiomatica in Haskell.
Alex Martelli,

@Alex - wrt Haskell e arg contano, non ho trascorso molto tempo su Haskell, e questo è stato tutto poche settimane fa. Quindi è stato un errore facile da fare.
Eric M,

101

Ecco un esempio concreto:

Supponiamo di avere una funzione che calcola la forza gravitazionale che agisce su un oggetto. Se non conosci la formula, puoi trovarla qui . Questa funzione accetta i tre parametri necessari come argomenti.

Ora, essendo sulla terra, vuoi solo calcolare le forze per gli oggetti su questo pianeta. In un linguaggio funzionale, potresti passare la massa della terra alla funzione e quindi valutarla parzialmente. Ciò che otterresti è un'altra funzione che accetta solo due argomenti e calcola la forza gravitazionale degli oggetti sulla terra. Questo si chiama curry.


2
Per curiosità, la libreria Prototype per JavaScript offre una funzione "curry" che fa praticamente esattamente quello che hai spiegato qui: prototypejs.org/api/function/curry
shuckster


7
Mi sembra un'applicazione parziale. La mia comprensione è che se si applica il curry, è possibile creare funzioni con un singolo argomento e comporle per formare funzioni più complicate. Mi sto perdendo qualcosa?
neontapir,

9
@neontapir è corretto. Quello che Shea ha descritto non è curry. È un'applicazione parziale. Se una funzione a tre argomenti è curry e la si chiama come f (1), ciò che si ottiene non è una funzione a due argomenti. Si ottiene indietro una funzione a argomento singolo che restituisce un'altra funzione a argomento singolo. Una funzione al curry può essere passata solo un argomento. Anche la funzione curry in PrototypeJS non sta eseguendo il curry. È un'applicazione parziale.
MindJuice,

no (alla valutazione parziale) e no (al curry). questa è nota come applicazione parziale. il curry è necessario per abilitarlo.
Will Ness,

47

Currying è una trasformazione che può essere applicata alle funzioni per consentire loro di accettare un argomento in meno rispetto al passato.

Ad esempio, in F # è possibile definire una funzione in questo modo: -

let f x y z = x + y + z

Qui la funzione f prende i parametri x, y e z e li somma insieme: -

f 1 2 3

Restituisce 6.

Dalla nostra definizione possiamo quindi definire la funzione curry per f: -

let curry f = fun x -> f x

Dove 'fun x -> fx' è una funzione lambda equivalente a x => f (x) in C #. Questa funzione immette la funzione che si desidera curry e restituisce una funzione che accetta un singolo argomento e restituisce la funzione specificata con il primo argomento impostato sull'argomento input.

Usando il nostro esempio precedente possiamo ottenere un curry di f così: -

let curryf = curry f

Possiamo quindi fare quanto segue: -

let f1 = curryf 1

Il che ci fornisce una funzione f1 che è equivalente a f1 yz = 1 + y + z. Ciò significa che possiamo fare quanto segue: -

f1 2 3

Che restituisce 6.

Questo processo è spesso confuso con 'applicazione di funzione parziale' che può essere definita in questo modo: -

let papply f x = f x

Sebbene possiamo estenderlo a più di un parametro, ovvero: -

let papply2 f x y = f x y
let papply3 f x y z = f x y z
etc.

Un'applicazione parziale prenderà la funzione e i parametri e restituirà una funzione che richiede uno o più parametri e, come mostrano i due esempi precedenti, viene implementata direttamente nella definizione della funzione F # standard in modo da poter ottenere così il risultato precedente: -

let f1 = f 1
f1 2 3

Che restituirà un risultato di 6.

In conclusione:-

La differenza tra l'applicazione del curry e l'applicazione della funzione parziale è che: -

Currying accetta una funzione e fornisce una nuova funzione accettando un singolo argomento e restituendo la funzione specificata con il suo primo argomento impostato su quell'argomento. Questo ci consente di rappresentare funzioni con più parametri come una serie di funzioni a argomento singolo . Esempio:-

let f x y z = x + y + z
let curryf = curry f
let f1 = curryf 1
let f2 = curryf 2
f1 2 3
6
f2 1 3
6

L'applicazione di funzione parziale è più diretta: accetta una funzione e uno o più argomenti e restituisce una funzione con i primi n argomenti impostati sugli n argomenti specificati. Esempio:-

let f x y z = x + y + z
let f1 = f 1
let f2 = f 2
f1 2 3
6
f2 1 3
6

Quindi i metodi in C # dovrebbero essere curry prima di poter essere parzialmente applicati?
cdmckay,

"Questo ci consente di rappresentare funzioni con parametri multipli come una serie di funzioni a argomento singolo" - perfetto, che mi ha chiarito tutto bene. Grazie
Analisi fuzzy,

44

Può essere un modo per utilizzare le funzioni per creare altre funzioni.

In javascript:

let add = function(x){
  return function(y){ 
   return x + y
  };
};

Ci permetterebbe di chiamarlo così:

let addTen = add(10);

Quando viene eseguito, 10viene passato come x;

let add = function(10){
  return function(y){
    return 10 + y 
  };
};

il che significa che ci viene restituita questa funzione:

function(y) { return 10 + y };

Quindi quando chiami

 addTen();

stai davvero chiamando:

 function(y) { return 10 + y };

Quindi se lo fai:

 addTen(4)

è lo stesso di:

function(4) { return 10 + 4} // 14

Quindi aggiungiamo addTen()sempre dieci a qualunque cosa passiamo. Possiamo fare funzioni simili allo stesso modo:

let addTwo = add(2)       // addTwo(); will add two to whatever you pass in
let addSeventy = add(70)  // ... and so on...

Ora l'ovvia domanda di follow-up è perché mai vorresti mai farlo? Trasforma quella che era un'operazione desiderosa x + yin una che può essere superata pigramente, il che significa che possiamo fare almeno due cose: 1. cache operazioni costose 2. raggiungere astrazioni nel paradigma funzionale.

Immagina che la nostra funzione al curry fosse così:

let doTheHardStuff = function(x) {
  let z = doSomethingComputationallyExpensive(x)
  return function (y){
    z + y
  }
}

Potremmo chiamare questa funzione una volta, quindi fare il giro del risultato per usarlo in molti posti, il che significa che facciamo le cose costose dal punto di vista computazionale solo una volta:

let finishTheJob = doTheHardStuff(10)
finishTheJob(20)
finishTheJob(30)

Possiamo ottenere astrazioni in modo simile.


5
La migliore spiegazione dettagliata di un processo intrinsecamente sequenziale che ho visto qui, e forse la migliore risposta più esplicativa del lotto.

4
@jonsilver Direi il contrario, non una buona spiegazione. Sono d'accordo che è bravo a spiegare l'esempio proposto, ma le persone tendono a non pensare, "sì perfettamente chiaro, ma avrei potuto fare la stessa cosa in un altro modo, quindi a cosa serve il curry?" In altre parole, vorrei che avesse abbastanza contesto o spiegazione per illuminare non solo come funziona il curry, ma anche perché non è un'osservazione inutile e banale rispetto ad altri modi per aggiungere dieci.
Whitneyland,

29

Una funzione curry è una funzione di diversi argomenti riscritti in modo tale che accetta il primo argomento e restituisce una funzione che accetta il secondo argomento e così via. Ciò consente alle funzioni di diversi argomenti di applicare parzialmente alcuni dei loro argomenti iniziali.


5
"Ciò consente alle funzioni di diversi argomenti di applicare parzialmente alcuni dei loro argomenti iniziali." - perché è utile?
Acarlon

5
Le funzioni di @acarlon sono spesso chiamate ripetutamente con uno o più argomenti uguali. Ad esempio, se si desidera eseguire mapuna funzione fsu un elenco di elenchi, xssè possibile farlo map (map f) xss.
Jon Harrop,

1
Grazie, ha senso. Ho letto un po 'di più ed è andato a posto.
Acarlon,

4
Penso che questa risposta sia corretta in un modo conciso. Il "curry" è il processo che prende la funzione di più argomenti e la converte in una serie di funzioni che ciascuna prende un singolo argomento e restituisce una funzione di un singolo argomento o, nel caso della funzione finale, restituisce il risultato effettivo . Questo può essere fatto automaticamente per te dalla lingua, oppure puoi chiamare una funzione curry () in altre lingue per generare la versione curry. Si noti che chiamare una funzione curry con un parametro non sta eseguendo il curry. Il curry è già successo.
MindJuice,

7

Ecco un esempio di giocattolo in Python:

>>> from functools import partial as curry

>>> # Original function taking three parameters:
>>> def display_quote(who, subject, quote):
        print who, 'said regarding', subject + ':'
        print '"' + quote + '"'


>>> display_quote("hoohoo", "functional languages",
           "I like Erlang, not sure yet about Haskell.")
hoohoo said regarding functional languages:
"I like Erlang, not sure yet about Haskell."

>>> # Let's curry the function to get another that always quotes Alex...
>>> am_quote = curry(display_quote, "Alex Martelli")

>>> am_quote("currying", "As usual, wikipedia has a nice summary...")
Alex Martelli said regarding currying:
"As usual, wikipedia has a nice summary..."

(Basta usare la concatenazione tramite + per evitare distrazioni per i programmatori non Python.)

Modifica per aggiungere:

Vedi http://docs.python.org/library/functools.html?highlight=partial#functools.partial , che mostra anche la distinzione tra oggetto parziale e funzione nel modo in cui Python lo implementa.


Non capisco: lo fai: >>> am_quote = curry (display_quote, "Alex Martelli") ma poi lo fai in seguito: >>> am_quote ("currying", "Come al solito, Wikipedia ha un bel riassunto. .. ") Quindi hai una funzione con due argomenti. Sembrerebbe che il curry dovrebbe darti tre diverse funzioni da comporre?
Eric M,

Sto usando il parziale per curry solo un parametro, producendo una funzione con due argomenti. Se lo desideri, puoi aggiungere al curriculum am_quote per crearne uno che citasse solo Alex su un argomento specifico. Il backgound matematico può essere focalizzato sul finire con funzioni con un solo parametro - ma credo che fissare qualsiasi numero di parametri come questo sia comunemente (se imprecisamente da un punto di vista matematico) chiamato curry.
Anon,

(a proposito - il '>>>' è il prompt nell'interprete interattivo Python, non parte del codice.)
Anon

OK grazie per il chiarimento su args. Conosco il prompt dell'interprete Python, stavo cercando di citare le righe ma non ha funzionato ;-)
Eric M

Dopo il tuo commento, ho cercato e trovato altri riferimenti, anche qui su SO, alla differenza tra "curry" e. "applicazione parziale" in risposta a molti casi dell'uso impreciso con cui ho familiarità. Vedere ad esempio: stackoverflow.com/questions/218025/…
Anon,

5

Currying sta traducendo una funzione da richiamabile f(a, b, c)a richiamabile come f(a)(b)(c).

Altrimenti il ​​curry avviene quando si scompone una funzione che accetta più argomenti in una serie di funzioni che prendono parte degli argomenti.

Letteralmente, il curry è una trasformazione di funzioni: da un modo di chiamare ad un altro. In JavaScript, di solito realizziamo un wrapper per mantenere la funzione originale.

Currying non chiama una funzione. Lo trasforma e basta.

Facciamo funzione curry che esegue il curry per funzioni a due argomenti. In altre parole, curry(f)per due argomenti lo f(a, b)traduce inf(a)(b)

function curry(f) { // curry(f) does the currying transform
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// usage
function sum(a, b) {
  return a + b;
}

let carriedSum = curry(sum);

alert( carriedSum(1)(2) ); // 3

Come puoi vedere, l'implementazione è una serie di wrapper.

  • Il risultato di curry(func)è un wrapper function(a).
  • Quando viene chiamato come sum(1), l'argomento viene salvato nell'ambiente lessicale e viene restituito un nuovo wrapper function(b).
  • Quindi sum(1)(2)chiama infine function(b)fornendo 2 e passa la chiamata alla somma multi-argomento originale.

4

Se capisci partialche sei a metà strada. L'idea di partialè preapplicare gli argomenti a una funzione e restituire una nuova funzione che vuole solo gli argomenti rimanenti. Quando viene chiamata questa nuova funzione, include gli argomenti precaricati insieme a tutti gli argomenti forniti.

In Clojure +è una funzione ma per rendere le cose nettamente chiare:

(defn add [a b] (+ a b))

Potresti essere consapevole che la incfunzione aggiunge semplicemente 1 a qualsiasi numero sia passato.

(inc 7) # => 8

Costruiamolo noi stessi usando partial:

(def inc (partial add 1))

Qui restituiamo un'altra funzione che ha 1 caricato nel primo argomento di add. Dato che addaccetta due argomenti, la nuova incfunzione vuole solo l' bargomento, non 2 argomenti come prima poiché 1 è già stato parzialmente applicato. Quindi partialè uno strumento dal quale creare nuove funzioni con valori predefiniti presupposti. Ecco perché in un linguaggio funzionale le funzioni spesso ordinano argomenti da generali a specifici. Ciò semplifica il riutilizzo di tali funzioni da cui costruire altre funzioni.

Ora immagina se il linguaggio fosse abbastanza intelligente da capire introspettivamente che addvoleva due argomenti. Quando gli abbiamo passato un argomento, piuttosto che l'espressione, se la funzione applicasse parzialmente l'argomento, lo abbiamo passato per nostro conto, capendo che probabilmente intendevamo fornire l'altro argomento in seguito? Potremmo quindi definire incsenza usare esplicitamente partial.

(def inc (add 1)) #partial is implied

Questo è il modo in cui alcune lingue si comportano. È eccezionalmente utile quando si desidera comporre le funzioni in trasformazioni più grandi. Ciò porterebbe a trasduttori.



3

Come tutte le altre risposte, il curry aiuta a creare funzioni parzialmente applicate. Javascript non fornisce supporto nativo per il curry automatico. Pertanto, gli esempi forniti sopra potrebbero non essere utili nella codifica pratica. C'è un ottimo esempio in livescript (che essenzialmente si compila in js) http://livescript.net/

times = (x, y) --> x * y
times 2, 3       #=> 6 (normal use works as expected)
double = times 2
double 5         #=> 10

Nell'esempio sopra quando hai dato meno no di argomenti livescript genera una nuova funzione al curry per te (doppio)


3

Curry può semplificare il tuo codice. Questo è uno dei motivi principali per utilizzare questo. Currying è un processo di conversione di una funzione che accetta n argomenti in n funzioni che accettano solo un argomento.

Il principio è passare gli argomenti della funzione passata, usando la proprietà di chiusura (chiusura), per memorizzarli in un'altra funzione e trattarla come un valore di ritorno, e queste funzioni formano una catena, e gli argomenti finali vengono passati per completare l'operazione.

Il vantaggio è che può semplificare l'elaborazione dei parametri trattando un parametro alla volta, il che può anche migliorare la flessibilità e la leggibilità del programma. Questo rende anche il programma più gestibile. Dividere anche il codice in pezzi più piccoli lo renderebbe riutilizzabile.

Per esempio:

function curryMinus(x) 
{
  return function(y) 
  {
    return x - y;
  }
}

var minus5 = curryMinus(1);
minus5(3);
minus5(5);

Posso anche fare ...

var minus7 = curryMinus(7);
minus7(3);
minus7(5);

Questo è ottimo per rendere il codice complesso pulito e per la gestione di metodi non sincronizzati ecc.


2

Una funzione curry viene applicata a più elenchi di argomenti, anziché a uno solo.

Ecco una normale funzione non curry, che aggiunge due parametri Int, xey:

scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int,y: Int)Int
scala> plainOldSum(1, 2)
res4: Int = 3

Ecco una funzione simile che è al curry. Invece di un elenco di due parametri Int, si applica questa funzione a due elenchi di un parametro Int ciascuno:

scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)Intscala> second(2)
res6: Int = 3
scala> curriedSum(1)(2)
res5: Int = 3

Quello che sta succedendo qui è che quando invochi curriedSum, ricevi effettivamente due invocazioni di funzioni tradizionali. La prima chiamata di funzione accetta un singolo parametro Int denominato xe restituisce un valore di funzione per la seconda funzione. Questa seconda funzione accetta il parametro Int y.

Ecco una funzione chiamata firstche fa nello spirito ciò che curriedSumfarebbe la prima invocazione della funzione tradizionale :

scala> def first(x: Int) = (y: Int) => x + y
first: (x: Int)(Int) => Int

Applicando 1 alla prima funzione - in altre parole, invocando la prima funzione e passando in 1 - si ottiene la seconda funzione:

scala> val second = first(1)
second: (Int) => Int = <function1>

Applicando 2 alla seconda funzione si ottiene il risultato:

scala> second(2)
res6: Int = 3

2

Un esempio di curry sarebbe quando disponi di funzioni che conosci solo uno dei parametri al momento:

Per esempio:

func aFunction(str: String) {
    let callback = callback(str) // signature now is `NSData -> ()`
    performAsyncRequest(callback)
}

func callback(str: String, data: NSData) {
    // Callback code
}

func performAsyncRequest(callback: NSData -> ()) {
    // Async code that will call callback with NSData as parameter
}

Qui, poiché non si conosce il secondo parametro per il callback durante l'invio, performAsyncRequest(_:)è necessario creare un altro lambda / chiusura per inviarlo alla funzione.


sta func callbacktornando da solo? Si chiama @ callback(str)così let callback = callback(str), callback è solo il valore di ritorno difunc callback
nikk wong

no, func callback(_:data:)accetta due parametri, qui ne do solo uno, il String, quindi è in attesa del prossimo ( NSData), ecco perché ora let callbackè un'altra funzione in attesa del passaggio dei dati
S2dent,

2

Ecco l'esempio della versione generica e la più breve per la funzione currying con n no. di params.

const add = a => b => b ? add(a + b) : a; 

const add = a => b => b ? add(a + b) : a; 
console.log(add(1)(2)(3)(4)());


1

Qui puoi trovare una semplice spiegazione dell'implementazione del curry in C #. Nei commenti, ho provato a mostrare come il curry può essere utile:

public static class FuncExtensions {
    public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
    {
        return x1 => x2 => func(x1, x2);
    }
}

//Usage
var add = new Func<int, int, int>((x, y) => x + y).Curry();
var func = add(1);

//Obtaining the next parameter here, calling later the func with next parameter.
//Or you can prepare some base calculations at the previous step and then
//use the result of those calculations when calling the func multiple times 
//with different input parameters.

int result = func(1);

1

Currying è una delle funzioni di ordine superiore di Java Script.

Currying è una funzione di molti argomenti che viene riscritta in modo tale da prendere il primo argomento e restituire una funzione che a sua volta utilizza gli argomenti rimanenti e restituisce il valore.

Confuso?

Vediamo un esempio,

function add(a,b)
    {
        return a+b;
    }
add(5,6);

Questo è simile alla seguente funzione di curry,

function add(a)
    {
        return function(b){
            return a+b;
        }
    }
var curryAdd = add(5);
curryAdd(6);

Cosa significa questo codice?

Ora leggi di nuovo la definizione,

Currying è una funzione di molti argomenti che viene riscritta in modo tale da prendere il primo argomento e restituire una funzione che a sua volta utilizza gli argomenti rimanenti e restituisce il valore.

Ancora confuso? Lasciami spiegare in profondità!

Quando chiami questa funzione,

var curryAdd = add(5);

Ti restituirà una funzione come questa,

curryAdd=function(y){return 5+y;}

Quindi, questo si chiama funzioni di ordine superiore. Significato, invocare una funzione a turno restituisce un'altra funzione è una definizione esatta per la funzione di ordine superiore. Questo è il più grande vantaggio per la leggenda, Java Script. Quindi torna al curry,

Questa riga passerà il secondo argomento alla funzione curryAdd.

curryAdd(6);

che a sua volta risulta,

curryAdd=function(6){return 5+6;}
// Which results in 11

Spero che tu capisca l'uso del curry qui. Quindi, venendo ai vantaggi,

Perché Currying?

Utilizza la riusabilità del codice. Meno codice, meno errore. Potresti chiedere come è meno codice?

Posso provarlo con lo script ECMA 6 nuove funzioni freccia funzioni.

Sì! ECMA 6, forniscici la meravigliosa funzione chiamata funzioni freccia,

function add(a)
    {
        return function(b){
            return a+b;
        }
    }

Con l'aiuto della funzione freccia, possiamo scrivere la funzione sopra come segue,

x=>y=>x+y

Va bene vero?

Quindi, meno codice e meno bug !!

Con l'aiuto di queste funzioni di ordine superiore si può facilmente sviluppare un codice privo di bug.

Ti sfido!

Spero, hai capito cosa sta succedendo. Non esitate a commentare qui se avete bisogno di chiarimenti.

Grazie buona giornata!


0

C'è un esempio di "Currying in ReasonML".

let run = () => {
    Js.log("Curryed function: ");
    let sum = (x, y) => x + y;
    Printf.printf("sum(2, 3) : %d\n", sum(2, 3));
    let per2 = sum(2);
    Printf.printf("per2(3) : %d\n", per2(3));
  };
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.