2010-02-18 13 views
10

Nie używając ich tak bardzo, nie jestem pewien, do czego służą wszystkie lambdy/bloki (inne niż mapowanie/zbieranie/czy/lekka składnia funkcji lokalnych). Jeśli niektórzy ludzie mogą zamieścić kilka interesujących, ale zrozumiałych przykładów (z wyjaśnieniem).Zabawa z Lambdas

preferowane języki dla przykładów: Python, Smalltalk Haskell

Odpowiedz

2

Można dokonać funkcjonalnej struktury danych z lambda. Oto prosta - wykaz funkcjonalny (Python), wspieranie add i contains metody:

empty = lambda x : None 

def add(lst, item) : 
    return lambda x : x == item or lst(x) 

def contains(lst, item) : 
    return lst(item) or False 

prostu zakodowane to szybko dla zabawy - Zauważ, że nie wolno dodawać żadnych wartości falsy jak jest. Nie jest też rekursywna, ponieważ powinna to być dobra struktura funkcjonalna. Ćwiczenia dla czytelnika!

+0

zmieni się to do pracy? def zawiera (lst, pozycja): return lst (przedmiot) lub brak –

2

Można ich użyć do sterowania przepływem. Na przykład w Smalltalk, metoda "ifTrue: ifFalse:" jest metodą dla obiektów Boolean, z inną implementacją dla każdej z klas True i False. Wyrażenie

someBoolean ifTrue: [self doSomething] ifFalse: [self doSomethingElse] 

wykorzystuje dwa zamknięcia --- bloków, w [nawiasach kwadratowych] w Smalltalk składni --- jeden dla prawdziwego oddziału, a drugi dla fałszywego oddziału. Realizacja „ifTrue: ifFalse:” dla instancji klasy Prawdziwego jest

ifTrue: block1 ifFalse: block2 
    ^block1 value 

i dla klasy Fałsz:

ifTrue: block1 ifFalse: block2 
    ^block2 value 

Zamknięcia, tutaj są używane do opóźnienia oceny tak, że decyzja o kontroli przepływu może być wzięty, bez specjalnej składni w ogóle (oprócz składni bloków).

Haskell jest trochę inny, a jego leniwy model oceny skutecznie automatycznie generuje efekt zamknięcia w wielu przypadkach, ale na Schemacie często używasz lambdas do sterowania przepływem. Na przykład, tutaj to narzędzie do pobierania wartości od stowarzyszenia liście, dostarczając ewentualnie obliczonych domyślnie w przypadku, gdy wartość nie jest obecna:

(define (assq/default key lst default-thunk) 
    (cond 
    ((null? lst) (default-thunk)) ;; actually invoke the default-value-producer 
    ((eq? (caar lst) key) (car lst)) 
    (else (assq/default key (cdr lst) default-thunk)))) 

To byłoby nazwać tak:

(assq/default 'mykey my-alist (lambda() (+ 3 4 5))) 

Kluczem tutaj jest użycie lambda, aby opóźnić obliczenie wartości domyślnej, dopóki nie będzie to wymagane.

Zobacz także kontynuację-mijanie-stylu, który prowadzi to do skrajności. JavaScript, na przykład, opiera się na kontynuowaniu przekazywania stylu i zamknięciach, aby wykonać wszystkie operacje blokujące (takie jak sen, operacje wejścia/wyjścia itp.).

ETA: Gdzie mówiłem zamknięcia powyżej, to znaczy leksykalnie zawężona zamknięć. Często jest to zakres leksykalny.

+0

Czy mógłbyś dodać opis leksykalnego zakresu? –

+0

@Roman: Określenie zakresu leksykalnego oznacza, że ​​jeśli masz funkcję taką jak 'f: = a -> (x -> (a ++) * x)', wywołanie 'f (2)' zwróci funkcję 'x - > (a ++) * x' z "a" związanym ze zmienną o wartości 2. Ponieważ jest to "a" z zakresu, w którym funkcja została zdefiniowana w sensie leksykalnym. To 'a' jest jednak całkowicie niezależne od' a' w funkcji zwróconej przez 'f (3)' lub inne wywołanie 'f (2)', ponieważ każde wywołanie tworzy nowe zamknięcie. –

1

Możesz użyć lambda, aby utworzyć kombinator Y, czyli funkcję, która przyjmuje inną funkcję i zwraca jej rekursywną formę.Oto przykład:

def Y(le): 
    def _anon(cc): 
     return le(lambda x: cc(cc)(x)) 
    return _anon(_anon) 

To myśl pałka, że zasługuje na więcej wyjaśnień, ale zamiast regurgitate tutaj sprawdzić this blog entry (powyżej próbka pochodzi stamtąd też).

0

Przykładem w Haskell obliczyć pochodną pojedynczej funkcji variabled stosując przybliżenie liczbowym:

deriv f = \x -> (f (x + d) - f x)/d 
    where 
    d = 0.00001 

f x = x^2 
f' = deriv f -- roughly equal to f' x = 2 * x 
1

swoim C#, ale ja osobiście mieć uciechę z tego artykułu za każdym razem czytam go:

Building Data out of Thin Air - implementacja funkcji Lispa, samochodów i cdr w języku C#. Pokazuje, jak zbudować prostą strukturę danych stosu całkowicie z funkcji lambda.

1

nie jest bardzo dość na tej samej zasadzie jak w Haskell itp, ale C# konstrukt Lambda jest (opcjonalnie) możliwość zestawiania do objcet modelu przedstawiającym kod (ekspresję drzew), a niż sam kod (jest to jeden z kamieni węgielnych LINQ).

To z kolei może prowadzić do bardzo ekspresyjnych możliwości meta-programowania, na przykład (gdzie lambda tu wyraża „daną usługę, co chcesz z tym zrobić?”):

var client = new Client<ISomeService>(); 
string captured = "to show a closure"; 
var result = client.Invoke(
    svc => svc.SomeMethodDefinedOnTheService(123, captured) 
); 

(zakładając odpowiednią sygnaturę Invoke)

Istnieje wiele zastosowań tego typu rzeczy, ale użyłem go do zbudowania stosu RPC, który nie wymaga generowania kodu runtime - po prostu analizuje wyrażenie drzewo, określa, co zamierzał wywołać, tłumaczy go na RPC, wywołuje go, zbiera odpowiedź, itp. (omówione więcej here).