Я уже довольно давно борюсь с лямбда-исчислением. Есть много ресурсов, которые объясняют, как уменьшить количество вложенных лямбда-выражений, но меньше, чтобы помочь мне в написании моих собственных лямбда-выражений.
Я пытаюсь написать рекурсивное решение Фибоначчи в Racket, используя чистое лямбда-исчисление (то есть функции с одним аргументом, числа Черча).
Вот определения церковных цифр, которые я использовал:
(define zero (λ (f) (λ (x) x)))
(define one (λ (f) (λ (x) (f x))))
(define two (λ (f) (λ (x) (f (f x)))))
(define three (λ (f) (λ (x) (f (f (f x))))))
(define four (λ (f) (λ (x) (f (f (f (f x)))))))
(define five (λ (f) (λ (x) (f (f (f (f (f x))))))))
(define six (λ (f) (λ (x) (f (f (f (f (f (f x)))))))))
(define seven (λ (f) (λ (x) (f (f (f (f (f (f (f x))))))))))
(define eight (λ (f) (λ (x) (f (f (f (f (f (f (f (f x)))))))))))
(define nine (λ (f) (λ (x) (f (f (f (f (f (f (f (f (f x))))))))))))
И это те функции с одним аргументом, которые я пытался включить:
(define succ (λ (n) (λ (f) (λ (x) (f ((n f) x))))))
(define plus (λ (n) (λ (m) ((m succ) n))))
(define mult (λ (n) (λ (m) ((m (plus n)) zero))))
(define TRUE (λ (t) (λ (f) t)))
(define FALSE (λ (t) (λ (f) f)))
(define COND (λ (c) (λ (x) (λ (y) ((c x) y)))))
(define iszero (λ (x) (x ((λ (y) FALSE) TRUE))))
(define pair (λ (m) (λ (n) (λ (b) (((IF b) m) n)))))
(define fst (λ (p) (p TRUE)))
(define snd (λ (p) (p FALSE)))
(define pzero ((pair zero) zero))
(define psucc (λ (n) ((pair (snd n)) (succ (snd n)))))
(define pred (λ (n) (λ (f) (λ (x) (((n (λ (g) (λ (h) (h (g f))))) (λ (u) x))(λ (u) u))))))
(define sub (λ (m) (λ (n) ((n pred) m))))
(define leq (λ (m) (λ (n) (iszero ((sub m) n))))) ;; less than or equal
(define Y ((λ (f) (f f)) (λ (z) (λ (f) (f (λ (x) (((z z) f) x))))))) ;; Y combinator
Я начал с написания рекурсивного Фибоначчи в Racket:
(define (fib depth)
(if (> depth 1)
(+ (fib (- depth 1)) (fib (- depth 2)))
depth))
Но в моих многочисленных попытках мне не удавалось написать его с использованием чистого лямбда-исчисления. Даже начать было нелегко.
(define fib
(λ (x) ((leq x) one)))
Который я звоню (например):
(((fib three) add1) 0)
Это, по крайней мере, работает (правильно возвращает ноль или единицу Church), но добавление чего-либо сверх этого все ломает.
У меня очень мало опыта работы с Racket, а лямбда-исчисление - это настоящая головная боль для человека, который никогда не использовал его до недавнего времени.
Я хотел бы понять, как построить эту функцию и включить рекурсию с комбинатором Y. Я особенно признателен за объяснение вместе с любым кодом. Было бы достаточно заставить его работать с fib(zero)
до fib(six)
, так как я могу беспокоиться о расширении определений Церкви в более позднее время.
РЕДАКТИРОВАТЬ:
Моя iszero
функция была в моей реализации скрытым саботажником. Вот правильная версия с обновленными логическими значениями из ответа Алекса:
(define iszero (λ (x) ((x (λ (y) FALSE)) TRUE)))
(define TRUE (λ (t) (λ (f) (t))))
(define FALSE (λ (t) (λ (f) (f))))
С этими изменениями и включением преобразователей все работает как надо!