Хаскелл Брукс Карри (1900-1982)
Некоторые возможности:
Любой терм t
лямбда-исчисления является одним из:
x
.λ
, переменной-параметром, точкой, затем произвольным термом – “телом”, напр. λx. x
(λx. x) y
. Правый терм будем называть аргументом.λx. x
λy. y
λz. z
λx. y
λy. x
Применение по правилу: вместо применения подставляется результат замены всех вхождений связанной переменной в теле на значение аргумента
Формально:
(λx. t₁) t₂ → [x → t₂] t₁
t₁
, t₂
– произвольные лямбда-термы, а выражение в квадратных скобках означает замену в следующем терме.Например, терм вида
(λx. x) (λy. y)
может быть редуцирован к
[x → (λy. y)]x
= (λy. y)
Рассмотрим типовые стратегии на примере терма
(λx. x) ((λy. y) (λz. (λw. w) z))
или для простоты
id (id (λz. id z))
где id
обозначает комбинатор идентичности, id = λx. x
.
(λx. x) ((λy. y) (λz. (λw. w) z))
→ (λx. x) ((λy. y) (λz. [w → z]w))
= (λx. x) ((λy. y) (λz. z))
→ [x → ((λy. y) (λz. z))]x
= (λy. y) (λz. z)
→ [y → (λz. z)]y
= λz. z
(λx. x) ((λy. y) (λz. (λw. w) z))
→ [x → ((λy. y) (λz. (λw. w) z))]x
= (λy. y) (λz. (λw. w) z)
→ [y → (λz. (λw. w) z)] y
= λz. (λw. w) z
→ λz. [w → z]w
= λz. z
(λx. x) ((λy. y) (λz. (λw. w) z))
→ [x → ((λy. y) (λz. (λw. w) z))]x
= (λy. y) (λz. (λw. w) z)
→ [y → (λz. (λw. w) z)]y
= λz. (λw. w) z
(λx. x) ((λy. y) (λz. (λw. w) z))
→ (λx. x) ([y → (λz. (λw. w) z)]y)
= (λx. x) (λz. (λw. w) z)
→ [x → (λz. (λw. w) z)]x
= λz. (λw. w) z
Рассмотрим некоторые типовые конструкции λ-исчисления, чтобы почувствовать, насколько это мощная система.
Рассмотрим вложенную абстракцию вида
λx. λy. λz. (x y) (x z)
При последовательном применении
(((λx. λy. λz. (x y) (x z)) u) v) w
получим
(u v) (u w)
семантически эквивалентно применению функции 3 аргументов к 3 аргументам.
Для удобства, введём сокращённое обозначение:
λx y …. t ≡ λx. λy. … t
условимся, что оператор применения лево-ассоциативен, т.е.
t₁ t₂ … tₙ ≡ ((t₁ t₂) …) tₙ
Определим:
tru ≡ λx y. x
fls ≡ λx y. y
Пусть tru
– “истина”, а fls
– “ложь”
Тогда определим комбинатор
ifThenElse = λc t f. c t f
функция 3 аргументов
если с ≡ tru
, ifThenElse c t f → t
если с ≡ fls
, ifThenElse c t f → f
ifThenElse
почти ничего не делает – его поведение закодировано в tru
и fls
.
Не составляет труда определить логические функции, например, конъюнкция
and = λx y. x y fls
Упражнение вывести выражения для or
, not
, xor
.
можно закодировать пары значений в виде термов. Введём определения
pair = λf s. λb. b f s
fst = λp. p tru
snd = λp. p fls
Определение pair
записано в таком виде, чтобы подчеркнуть, что применение pair
к двум аргументам возвращает функцию.
Например,
fst (pair u v)
= (λp. p tru) ((λf s. λb. b f s) u v)
→ (λp. p tru) (λb. b u v)
→ (λb. b u v) tru
→ tru u v
= (λx y. x) u v
→ u
Стандартная конструкция натуральных чисел – числа Чёрча – выглядит следующим образом:
c₀ ≡ λs z. z
c₁ ≡ λs z. s z
c₂ ≡ λs z. s (s z)
c₃ ≡ λs z. s (s (s z))
...
Число n
кодируется комбинатором двух аргументов cₙ
,
принимает “функцию следования” s
и “ноль” z
n
раз применяет s
к z
.
В кодировании Чёрча, число n
– функция, которая что-то делает n
раз.
Определим функцию следования, которая возвращает следующее за данным число Чёрча:
succ = λn. λs z. s (n s z)
succ
.Аналогично можно определить сложение
plus = λm n. λs z. m s (n s z)
и умножение
times = λm n. λs z. m (n s) z
plus
и times
через succ
и plus
соответственноДля проверки на равенство 0
iszero = λn. n (λx. fls) tru
zz = pair c₀ c₀
ss = λnn. pair (snd nn) (succ (snd nn))
pred = λn. fst (n ss zz)
pred c₀ → c₀
pred
Ω = (λx. x x) (λx. x x)
Ω
: (λx. x x) (λx. x x)
→ [x → (λx. x x)](x x)
= (λx. x x) (λx. x x)
Ω
можно обобщить до более полезного комбинатора – комбинатора неподвижной точки, который позволяет использовать рекурсию:fix = λf. (λx. f (λy. x x y)) (λx. f (λy. x x y))
достаточно сложная структура с повторами
Смысл достаточно прост:
мы хотим ввести рекурсию, то есть возможность пользоваться конструкциями вида
f = <тело, содержащее f>
Для этого собственно и используется комбинатор fix:
f = fix (λf. <тело, содержащее f>)
fact1 = λf. λn. ifThenElse (iszero n) c₁ (times n (f (pred n)))
f
– рекурсивный вызов.fix
, можем записать функцию факториала какfact = fix fact1
fact1 = λf. λn. ifThenElse (iszero n) c₁ (times n (f (pred n)))
fact = fix fact1
Рассмотрим, как будет происходить редукция, скажем, выражения fact c₂
fact c₂
= fix fact1 c₂
= (λf. (λx. f (λy. x x y)) (λx. f (λy. x x y))) fact1 c₂
→ (λx. fact1 (λy. x x y)) (λx. fact1 (λy. x x y)) c₂
→ fact1 (λy. (λx. fact1 (λy. x x y)) (λx. fact1 (λy. x x y)) y) c₂
= fact1 (λz. (λx. fact1 (λy. x x y)) (λx. fact1 (λy. x x y)) z) c₂
→ ... →
times c₂ ((λz. (λx. fact1 (λy. x x y)) (λx. fact1 (λy. x x y)) z) c₁)
→ times c₂ ((λx. fact1 (λy. x x y)) (λx. fact1 (λy. x x y)) c₁)
→ ... →
times c₂ (times c₁ ((λx. fact1 (λy. x x y)) (λx. fact1 (λy. x x y)) c₀))
→ ...
→ times c₂ (times c₁ c₁)
→ ...
→ c₂