Cos'è questa "Lambda" di cui tutti parlano?


93

Cos'è questa "Lambda" di cui tutti parlano? Molte persone sembrano adorarlo, ma tutto quello che posso dedurre da esso è che è solo un modo per racchiudere molte righe di codice in un'unica espressione.

Qualcuno può per favore illuminarmi sul suo vero valore?


16
Posso far notare a chi risponde che l'interrogante non menziona da nessuna parte .net


Domanda cruciale. Grazie per avermelo chiesto.
Peanut

I Lambda appartengono al mondo della programmazione funzionale (programmazione dichiarativa).
RBT

Risposte:


179

Funziona senza nome

In poche parole, un lambda è una funzione senza nome o una funzione anonima. Un piccolo pezzo di codice eseguibile, che può essere passato in giro come se fosse una variabile. In JavaScript:

function () {}; // very simple

Vediamo ora alcuni usi per questi lambda.

Astrazione del codice boilerplate

Lambdas può essere utilizzato per astrarre il codice boilerplate. Ad esempio i loop. Siamo abituati a scrivere fore fare whileloop tutto il giorno. Ma questo è un codice che non si scrive. Potremmo estrarre il codice all'interno del ciclo, la parte più importante del ciclo, e astrarre il resto:

for (var i=0; i<array.length; i++) {
    // do what something useful with array[i]
}

utilizzando gli forEachoggetti array of, diventa:

array.forEach(function (element, index) {
   // do something useful with element
   // element is the equivalent of array[i] from above
});

L'astrazione di cui sopra potrebbe non essere così utile, ma ci sono altre funzioni di ordine superiore, come forEach, che eseguono compiti molto più utili. Ad esempio filter:

var numbers = [1, 2, 3, 4];
var even    = [];

// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        even.push(numbers[i]);
    }
}

alert(even);

// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
    return number % 2 === 0;
});

alert(even);

Ritardo di esecuzione del codice

In alcuni ambienti, in cui è disponibile il concetto di evento, potremmo usare lambda per rispondere a eventi che possono accadere in un determinato momento.

window.onload = function () {
    alert("Loaded");
};

window.setTimeout(function () {
    alert("Code executed after 2 seconds.");
}, 2000);

Questo avrebbe potuto essere fatto in altri modi, ma quelli sono piuttosto prolissi. Ad esempio, in Java c'è l' Runnableinterfaccia.

Fabbriche di funzioni

Fino a questo punto, abbiamo utilizzato principalmente lambda per le sue capacità di zucchero sintattico. Ma ci sono situazioni in cui i lambda possono essere molto più utili. Ad esempio, potremmo avere funzioni che restituiscono lambda. Supponiamo di avere una funzione che vogliamo che i suoi valori di ritorno vengano memorizzati nella cache.

var users = [];
var getUser = function (name) {
    if (! users[name]) {
        // expensive operations to get a user. Ajax for example
        users[name] = user_from_ajax;
    }

    return users[name];
};

In seguito, potremmo notare che abbiamo una funzione simile:

var photos = [];
var getPhoto = function (name) {
    if (! photo[name]) {
        // expensive operations to get a user. Ajax for example
        photos[name] = photo_from_ajax;
    }

    return photos[name];
};

C'è chiaramente uno schema lì dentro, quindi astraggiamolo. Usiamo la memoizzazione .

/**
 * @param {Array}     store Data structure in which we cache lambda's return values
 * @param {Function}  lambda
 * @return {Function} A function that caches the result of calling the lambda param
 */
var memoize = function (store, lambda) {
    // return a new lambda
    return function (name) {
        if (! store[name]) {
            // Execute the lambda and cache the result
            store[name] = lambda(name);
        }

        return store[name];
    };
};

var getUsers = memoize([], function (name) {
    // expensive operations to get a user. Ajax for example
});

var getPhotos = memoize([], function (name) {
    // expensive operations to get a photo. Ajax for example
});

Come puoi vedere, usando lambda, siamo stati in grado di astrarre la logica di caching / memoization. Se per l'altro esempio ci fossero delle soluzioni alternative, credo che questo particolare problema sia difficilmente risolvibile utilizzando altre tecniche. Siamo riusciti a estrarre alcuni importanti codici boilerplate in un unico posto. Per non parlare del fatto che ci siamo sbarazzati delle variabili globali userse photos.

Guardando il tuo profilo vedo che sei principalmente un utente Python. Per il modello sopra, Python ha il concetto di decoratori. Ci sono molti esempi in rete per i decoratori di memoization . L'unica differenza è che in Python molto probabilmente hai una funzione annidata con nome all'interno di quella funzione decoratore. Il motivo è che Python supporta solo espressioni lambda a singola espressione. Ma il concetto è lo stesso.

Come esempio di utilizzo lambda di Python. Il codice sopra in cui abbiamo filtrato i numeri pari può essere rappresentato in Python in questo modo:

filter(lambda x: x % 2 == 0, [1, 2, 3, 4])

Ad ogni modo, i lambda non sono così potenti senza chiusure. Le chiusure sono ciò che rende il concetto di lambda così potente. Nel mio esempio di memoizzazione ho usato delle chiusure per creare una chiusura attorno al storeparametro. In questo modo, ho accesso a quel parametro anche dopo che la memoizefunzione ha restituito il suo risultato (un lambda).


3
Wow, ci dedichi molto tempo.
mk12

4
@ Mk12, nella scrittura effettiva della risposta, non proprio. Nell'imparare queste cose, sì, è passato del tempo da quando ho iniziato :)
Ionuț G. Stan

Buona risposta ma mancano informazioni sulle "interfacce funzionali" (dal punto di vista Java).
Djangofan

Cosa sono questi operatori "===" nel tuo "codice boilerplate astratto"?
Don


19

Il termine "lambda" viene utilizzato per fare riferimento a una funzione anonima, solitamente una chiusura . Sono utili perché consentono di scrivere funzioni che utilizzano altre funzioni senza gonfiare inutilmente il codice. Ad esempio, in Ruby:

(1..100).select {|num| num % 2 == 0}

Questo creerà un array contenente i numeri pari tra 1 e 100. Non dobbiamo scrivere un ciclo esplicito: il metodo select accetta una funzione che usa per testare i valori, quindi tutto ciò di cui abbiamo bisogno è la nostra logica personalizzata. Questo ci consente di personalizzare notevolmente il metodo praticamente senza alcuno sforzo o sovraccarico. Fondamentalmente, possiamo comporre funzioni da funzioni più piccole.

Questo è solo un semplice esempio di ciò che possono fare. La capacità di passare funzioni come dati è davvero potente e i programmatori di linguaggi funzionali fanno abitualmente cose davvero sorprendenti con esso.


6
Forse dovresti aggiungere che la cosa all'interno dei tubi è il parametro. Sono una di queste persone che hanno problemi a leggere Ruby.
Skurmedel

Questa è una bella risposta. L'unico motivo per cui Ionut ha ottenuto il mio voto è che ci ha detto perché dovremmo preoccuparci (in dettaglio) dei lambda.
Frank Shearar

Non sono d'accordo sul fatto che i lambda di solito siano chiusure.
jwg

6

"Lambda" forse troppo pochi. Dai un'occhiata al Lambda calcolo . È utile nella programmazione funzionale.

E la programmazione funzionale è ancora un altro paradigma di programmazione (come procedurale o orientato agli oggetti).


5
Poi si parla di "Lambda", molto probabilmente si parla di funzione anonima, puntatori a funzione, chiusura o qualcosa di simile. Quasi mai si riferiscono alla cosa reale del lambda calcolo.
J-16 SDiZ

Sono contento che tu abbia menzionato il calcolo Lambda.! +1.
RBT

5

I lambda in .NET vengono spesso definiti "zucchero sintattico". Non influenzano direttamente la funzionalità, tuttavia rendono la lingua più facile da usare per le persone.

Quando avrai capito il potere di usarli, sono sicuro che scoprirai che scriverai meno codice rispetto al vecchio metodo usando delegati / metodi anonimi.


1
Non credo che nessuno abbia menzionato .NET, quindi l'OP è probabilmente meglio con una risposta più generale.
molf

2
questo è il motivo per cui ho chiarito in risposta a parlare di .net. Se altri cinguettano con la loro implementazione linguistica, le domande e risposte aiuteranno molte persone, indipendentemente dalla loro scelta linguistica.
redsquare

Questa risposta sembra che tu abbia sentito qualcosa sui lambda, ma tu stesso non li capisci ancora.
jwg

2

Dr Dobbs Journal ha un utile articolo che introduce le espressioni lambda (nel contesto del C ++ ma penso che tu possa applicare i principi a qualsiasi linguaggio).

Come dice l'articolo: "Un'espressione lambda è un'espressione molto compatta che non richiede una definizione di classe / funzione separata".

Quindi, usando gli esempi degli elenchi 1 e 2 di DDJ invece di scrivere:

std::for_each( vec.begin(), vec.end(), print_to_stream<std::string>(std::cout));

Che richiede una definizione di classe separata come:

template <typename T, typename Stream> class print_to_stream_t {
  Stream& stream_;
public:
  print_to_stream_t(Stream& s):stream_(s) {}
  void operator()(const T& t) const {
    stream_ << t;
  }
};
template <typename T,typename Stream> 
print_to_stream_t<T,Stream>   print_to_stream(Stream& s) {
  return print_to_stream_t<T,Stream>(s);
}

Utilizzando la libreria Boost lambda questo può diventare:

std::for_each(vec.begin(),vec.end(),std::cout << _1);

Ciò mantiene la definizione in linea.

L'articolo spiega anche alcune altre applicazioni delle espressioni lambda.

Penso che un punto chiave nell'articolo DDJ sia "In genere, le espressioni lambda vengono utilizzate quando sono necessarie funzioni piccole e non eccessivamente complesse nel sito della chiamata. Se la funzione non fosse banale, non vorresti un'espressione lambda ma una funzione normale o un oggetto funzione. "


2

Se hai mai lavorato con funzioni / metodi che usano puntatori a funzione, delegati, strategia o gestione di pattern / eventi dell'osservatore e hai pensato a te stesso "Sto scrivendo l'intera funzione solo per usarla una sola volta - per passarla a questo metodo ; Vorrei poterlo scrivere sul posto, piuttosto che ingombrare il mio codice "- è lì che potresti usare le funzioni Lambda. I linguaggi che supportano questo costrutto di solito sfruttano anche pesantemente il concetto di passare le funzioni come parametri, in particolare per quanto riguarda il lavoro con le liste (funzioni di prima classe e funzioni di ordine superiore). Ciò è particolarmente vero per i linguaggi funzionali, che si basano sulla composizione delle funzioni piuttosto che sulla modifica della memoria per i calcoli. In alcuni casi (in linguaggi come Python),


2

"lambda" in quanto parola è la terminologia dei giorni in cui i tipi di informatica avevano la stessa probabilità di essere formati in matematica o logica rispetto a una laurea in informatica. Alcuni di loro hanno elaborato un paradigma chiamato "programmazione funzionale", abbastanza diverso dall'imperativo e anche abbastanza potente. AFAIK questo è l'ambiente in cui il termine è entrato in uso.

Matematici e logici sono portati a usare parole strane.

"lambda" suona davvero esoterico, come se fosse una cosa molto strana e speciale. In realtà, se scrivi JavaScript per un'applicazione browser web e usi l'idioma "var foo = function () {...}", hai sempre utilizzato le funzioni lambda.


1

Un'espressione lambda è una semplice forma di funzione. L'idea è che qualcosa della forma a sinistra (equivalente a parametri) diventi qualcosa della forma a destra (equivalente al corpo).

ad esempio, in do diesis:

x => x * x

è un lambda per quadrare un valore. Qualcosa della forma

x

diventa qualcosa della forma

x * x

0

"Un'espressione lambda è una funzione anonima che può contenere espressioni e istruzioni e può essere utilizzata per creare delegati o tipi di albero delle espressioni.

Tutte le espressioni lambda utilizzano l'operatore lambda =>, che viene letto come "va a". Il lato sinistro dell'operatore lambda specifica i parametri di input (se presenti) e il lato destro contiene l'espressione o il blocco di istruzioni. L'espressione lambda x => x * x viene letta "x va ax volte x".

da MSDN


4
Sì, Microsoft fa pensare a tutti di averlo inventato. Le espressioni lambda sono precedenti a Microsoft, però. È un termine matematico che è stato applicato a diversi linguaggi di programmazione. (Il che è possibile, dal momento che la matematica potrebbe essere considerata di per sé un linguaggio informatico.)
Wim ten Brink

4
Nota che questo è specifico per l'implementazione .Net di Microsoft. Non è una grande deviazione dall'idea generale di lambda, ma penso che la funzionalità implementata in Lisp sia più "standard".
Chuck

2
Quella risposta non spiega affatto cos'è un Lambda (necessita di definizioni di funzione anonima, delegato, tipo di albero delle espressioni) e certamente non spiega qual è il suo valore.
danio

0

Per una spiegazione completa sulle espressioni Lambda, controlla anche Wikipedia . (Scorri verso il basso fino alla parte Lambda calcolo e linguaggi di programmazione .) Le espressioni lambda non sono così nuove e non sono solo parte di C #, ma qualcosa che è stato introdotto nell'elaborazione quasi 80 anni fa! Le espressioni lambda sono la base per la programmazione funzionale.

È un valore? Bene, considerando che in realtà è piuttosto vecchio, direi: molto prezioso per chiunque faccia calcoli.


0

Se ti piace Java, hai sentito molto parlare di lambda o chiusure negli ultimi due mesi, perché c'erano diverse proposte per l'aggiunta di questa funzionalità a Java 7. Tuttavia, penso che il comitato l'abbia abbandonato. Una delle proposte è di Neal Gafter e spiegata in dettaglio qui: javac.info . Questo mi ha aiutato a capire i casi d'uso e i vantaggi (specialmente rispetto alle classi interne)




-1

Sì, è solo un modo per racchiudere molte righe di codice in un'unica espressione. Ma essendo così efficiente, consente nuovi modi di strutturare il tuo programma.

Spesso si evita di scrivere delegati o callback e si torna allo stile procedurale semplicemente perché dichiarare nuove funzioni o classi per una singola espressione è troppo faticoso.

Le espressioni lambda rendono utile utilizzare i callback anche per le attività più piccole, il che potrebbe rendere il codice più chiaro. Forse no.

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.