Забава с лямбдами

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

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

10
задан 6 revs, 5 users 57% 21 April 2015 в 04:33
поделиться

6 ответов

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

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

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

2
ответ дан 4 December 2019 в 02:50
поделиться

Вы можете использовать их для потока управления. Например, в 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 немного отличается: его модель отложенного вычисления во многих случаях эффективно автоматически создает эффект замыканий, но в Scheme вы в конечном итоге часто используете лямбды для потока управления. Например, вот утилита для извлечения значения из списка ассоциаций, предоставляющая необязательно вычисляемое значение по умолчанию в случае, если значение отсутствует:

(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
ответ дан 4 December 2019 в 02:50
поделиться

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

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

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

1
ответ дан 4 December 2019 в 02:50
поделиться

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

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

1
ответ дан 4 December 2019 в 02:50
поделиться

Пример в 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
0
ответ дан 4 December 2019 в 02:50
поделиться

Это не совсем полностью та же концепция, что и в 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
ответ дан 4 December 2019 в 02:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: