Веселье с лямбдами - PullRequest
       81

Веселье с лямбдами

10 голосов
/ 19 февраля 2010

Я не совсем уверен, что они использовали их все время. Я не совсем уверен, для чего можно использовать все лямбды / блоки (кроме синтаксиса map / collect / do / lightweight local function). Если бы некоторые люди могли опубликовать несколько интересных, но несколько понятных примеров (с объяснением).

предпочтительные языки для примеров: python, smalltalk, haskell

Ответы [ 6 ]

2 голосов
/ 19 февраля 2010

Вы можете использовать их для управления потоком. Например, в Smalltalk метод ifTrue: ifFalse: является методом для логических объектов, с различной реализацией для каждого из классов True и False. Выражение

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

использует два замыкания - блоки в [квадратных скобках] в синтаксисе Smalltalk - одно для истинной ветви и одно для ложной ветви. Реализация «ifTrue: ifFalse:» для экземпляров класса True -

ifTrue: block1 ifFalse: block2
    ^ block1 value

и для класса False:

ifTrue: block1 ifFalse: block2
    ^ block2 value

Здесь замыкания используются для задержки оценки, чтобы можно было принять решение о потоке управления, без какого-либо специального синтаксиса вообще (кроме синтаксиса для блоков).

Haskell немного отличается, поскольку его ленивая модель оценки во многих случаях эффективно автоматически создает эффект замыканий, но в Схеме вы в конечном итоге часто используете лямбда-выражения для потока управления. Например, вот утилита для извлечения значения из списка ассоциаций, предоставляющая опционально вычисляемое значение по умолчанию в случае, если значение отсутствует:

(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))))

Это будет называться так:

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

Ключевым моментом здесь является использование лямбда-выражения для задержки вычисления значения по умолчанию до тех пор, пока оно фактически не станет обязательным.

См. Также стиль прохождения продолжения, который доводит это до крайности. Например, Javascript полагается на стиль продолжения продолжения и замыкания для выполнения всех своих операций блокировки (таких как спящий режим, ввод-вывод и т. Д.).

ETA : Там, где я говорил о замыканиях выше, я имею в виду лексически ограниченные замыкания. Часто это ключевая лексическая сфера.

2 голосов
/ 19 февраля 2010

Вы можете сделать функциональную структуру данных из лямбд.Вот простой - функциональный список (Python), поддерживающий методы add и contains:

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

Я просто написал это быстро для забавы - обратите внимание, что вы не можете добавлять какие-либоложные значения как есть.Она также не является хвостовой рекурсивной, как должна быть хорошая функциональная структура.Упражнения для читателя!

1 голос
/ 26 февраля 2010

Это на самом деле не совсем та же концепция, что и в haskell и т. Д., Но в C # лямбда-конструкция имеет (необязательно) возможность компилирования в модель объекта, представляющую код (деревья выражений), а не сам код (это один из краеугольных камней LINQ).

Это, в свою очередь, может привести к некоторым очень выразительным возможностям метапрограммирования, например (где лямбда-выражение выражает «данный сервис, что вы хотите с ним делать?»):

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

(при условии подходящей Invoke подписи)

Существует множество вариантов использования этого типа вещей, но я использовал его для создания стека RPC, который не требует генерации кода во время выполнения - он просто анализирует дерево выражений, выясняет, что имел в виду вызывающий объект, переводит его в RPC, вызывает его, собирает ответ и т. д. (обсуждается подробнее здесь ).

1 голос
/ 25 февраля 2010

Это C #, но я лично получаю удовольствие от этой статьи каждый раз, когда читаю ее:

Построение данных из Thin Air - реализация функций Lisp's cons, car и cdr в C #. Он показывает, как построить простую структуру данных стека полностью из лямбда-функций.

1 голос
/ 21 февраля 2010

Вы можете использовать лямбду для создания Y Combinator, то есть функции, которая принимает другую функцию и возвращает ее рекурсивную форму.Вот пример:

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

Это мыслительная дубинка , которая заслуживает некоторого дополнительного объяснения, но вместо того, чтобы извергать ее здесь, проверьте этот блогзапись (вышеприведенный образец тоже оттуда).

0 голосов
/ 24 февраля 2010

Пример в Haskell для вычисления производной функции с одной переменной с использованием числового приближения:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...