Изменения
→Логические значения
чтобы красиво написать функцию <tex>\operatorname{if}</tex>:
<tex>\operatorname{if} = \lambda p \to \lambda t \to \lambda e \to p \ t \ e</tex>
Если ей в качестве первого аргумента дадут <tex>\operatorname{true}</tex>, то вернётся <tex>t</tex>, иначе {{---}} <tex>e</tex>.
Стандартные функции булевой логики:
<tex>\operatorname{and} = \lambda n \to \lambda m \to \operatorname{if} n \ m \ \operatorname{false}</tex>
<tex>\operatorname{or} = \lambda n \to \lambda m \to \operatorname{if} n \ \operatorname{true} m</tex>
<tex>\opeartornameoperatorname{not} = \lambda b \to \opeartornameoperatorname{if} b \ \operatorname{false} \operatorname{true}</tex>
Ещё одной важной функцией является функция проверки, является ли число нулём:
<tex>\operatorname{isZero} = \lambda n \to n \ (\lambda c \to \operatorname{false}) \ \operatorname{true}</tex>
Функция выглядит несколько странно. <tex>\lambda c -> \operatorname{false}</tex> {{---}} функция, которая независимо
вернётся <tex>\operatorname{false}</tex>.
<tex>\beginoperatorname{codepair}pair' = Lam "\lambda a" $ Lam "\to \lambda b" $ Lam "\to \lambda t" $ Var "\to t" `App` Var "\ a" `App` Var "\ b"fst'' = Lam "p" $ Var "p" `App` true'snd'' = Lam "p" $ Var "p" `App` false'\end{code}</tex>
<tex>\subsectionoperatorname{Вычитаниеsnd}В отличие от всех предыдущих функций, вычитание для натуральных чисел определенотолько в случае, если уменьшаемое больше вычитаемого. Положим в противном случаерезультат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу.Тогда на её основе легко сделать, собственно, вычитание.= \lambda p \to p\ \operatorname{false}</tex>
Функция <tex>\beginoperatorname{codepair}minus' = Lam "n" $ Lam "m" $ Var "m" `App` pred' `App` Var "n"</tex> принимает два значения и запаковывает их в пару так, чтобы к ним можно было обращаться по <tex>\endoperatorname{codefst}</tex> и <tex>\operatorname{snd}</tex>. В <tex>\operatorname{fst}</tex> и <tex>\operatorname{snd}</tex> вместо <tex>t</tex> в <tex>\operatorname{pair}</tex> будет подставлено <tex>\operatorname{true}</tex> или <tex>\operatorname{false}</tex>, возвращающие, соответственно, первый и второй аргументы, то есть <tex>a</tex> или <tex>b</tex>, соответственно.
Осталось, собственно, функция для вычитания единицы. Однако, это не так просто, как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет проблематично. Если вы ничего попробовать воспользоваться идеей о том, чтобы, начав от нуля, идти вперёд, и пройти на один шаг меньше, то будет не понялиочень понятно, как же остановиться ровно за один шаг до конца. Для реализации вычитания единицы сделаем следующее. <tex>n</tex> раз выполним следующее: имея пару <tex>\langle n-1, n-2\rangle</tex> построим пару <tex>\langle n, не огорчайтесьn-1\rangle</tex>. Вычитание придумал КлиниТогда после <tex>n</tex> шагов во втором элементе пары будет записано число <tex>n-1</tex>, когда ему вырывали зуб мудростикоторое и хочется получить. А сейчас наркоз уже не тот!
<tex>\subsectionoperatorname{Сравнениеpred}= \lambda n \to \lambda s \to \lambda z \to\ \operatorname{snd} (Так как вычитание определено таким способом, чтобы для случая, в котором n\ (уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить \lambda p \to \operatorname{pair}\ (s\ (\operatorname{fst} p))\ (\operatorname{fst} p)сравнение на больше-меньше через него. Равными же числа $a$ и $b$ считаются, если $a - b = 0 )\ (\operatorname{pair}\ z\wedge b - a = 0$.z)</tex>
<tex>\beginoperatorname{specle}fact = \x -> if (lambda n \to \lambda m \to \operatorname{isZero x) one }\ (fact (pred x))\endoperatorname{specminus}\ n\ m)</tex>
<tex>\beginoperatorname{speceq}fact = (\f -> lambda n \to \lambda m \to \operatorname{and}\x -> if (\operatorname{isZero x) one }\ (f (pred x\operatorname{minus}\ n\ m))) fact\ (\operatorname{isZero}\end(\operatorname{specminus}\ m\ n))</tex>
Мы столкнулись с проблемой. В определении функции <tex>\beginoperatorname{codefact}fix' = Lam "f" $ (Lam "x" $ Var "f" `App` (Var "x" `App` Var "x")) `App` (Lam "x" $ Var "f" `App` (Var "x" `App` Var "x"))</tex> используется функция <tex>\endoperatorname{codefact}</tex>. При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом
<tex>\operatorname{fact} = (\lambda f \to \lambda x \to \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (f\ (\operatorname{pred}\ x)))\ \operatorname{fact}</tex> {{Определение|definition=''Неподвижной точкой'' лямбда-функции <tex>f</tex> назовём такую функцию <tex>x</tex>, что<tex>f\ x \to_\beta x</tex>. }} Лямбда исчисление обладаем замечательным свойством: у каждой функции есть неподвижная точка! Рассмотрим следующую функцию. <tex>\operatorname{fix} = \lambda f \to (\lambda x \to f\ (x\ x))\ (\lambda x \to f\ (x\ x))</tex> Заметим, что $<tex>\operatorname{fix' } \to_\beta \lambda f \to f \ ((\lambda x \to f \ (x \ x)) \ (\lambda x \to f \ (x \ x)))$</tex>.
Или, что то же самое,
Рассмотрим функцию
<tex>\beginoperatorname{code}fact'' } = Lam "\lambda f" $ Lam "\to \lambda x" $ \to \operatorname{if'' `App` }\ (\operatorname{isZero' `App` Var "}\ x") `App` one' `App` \ \bar 1\ (\operatorname{mult' `App` Var "}\ x" `App` \ (Var "f" `App` \ (\operatorname{pred' `App` Var "}\ x")))\end{code}</tex>
Как было показано выше, $<tex>\operatorname{fix } f \to_\beta f \ (\operatorname{fix } f)$</tex>, то есть, $<tex>\operatorname{fix }\ \operatorname{fact'' } \to_\beta \operatorname{fact'$}</tex>, где $<tex>\operatorname{fact'$~}</tex> {{--- }} искомая функция, считающая факториал.
<tex>\beginoperatorname{codefact}fact' = \operatorname{fix' `App` }\ \operatorname{fact''\end{code}</tex>
Это даст функцию, которая посчитает факториал числа. Но делать она это будет мееедленно-меееедленно. Для того, чтобы посчитать $<tex?5!$ </tex> потребовалось сделать66066 $<tex>\beta$</tex>-редукций.
Тут правда ничего не понятно? :'(
<tex>\beginoperatorname{code}div'' } = Lam "\lambda div" $ Lam "\to \lambda n" $ Lam "\to \lambda m" $ \to \operatorname{if'' `App` }\ (\operatorname{less' `App` Var "}\ n" `App` Var "\ m") `App` zero' `App` \ \bar 0\ (\operatorname{succ' `App` }\ (Var "div" `App` \ (\operatorname{minus' `App` Var "}\ n" `App` Var "\ m") `App` Var "\ m"))</tex> <tex>\operatorname{div' } = \operatorname{fix' `App` }\ \operatorname{div''\end{code}</tex>
И остатка от деления
<tex>\beginoperatorname{code}mod'' } = Lam "\lambda mod" $ Lam "\to \lambda n" $ Lam "\to \lambda m" $ \to \operatorname{if'' `App` }\ (\operatorname{less' `App` Var "}\ n" `App` Var "\ m") `App` Var "\ n" `App` \ (Var "mod" `App` \ (\operatorname{minus' `App` Var "}\ n" `App` Var "\ m") `App` Var "\ m")</tex> <tex>\operatorname{mod} = \operatorname{fix}\ \operatorname{mod' }</tex> ===Проверка на простоту=== fix <tex>\operatorname{isPrimeHelp}</tex> {{---}} принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от 2 до <tex>p-1</tex>. Если на что-нибудь разделилось, то число {{---}} составное, иначе {{---}} простое. <tex>\operatorname{isPrimeHelp' `App` } =</tex><tex>\lambda f \to \lambda p \to \lambda i \to \operatorname{if}\ (\operatorname{le}\ p\ i)\ \operatorname{true}\ (\operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ p\ i))\ \operatorname{false}\ (f\ p\ (\operatorname{succ}\ i)))</tex> <tex>\operatorname{isPrimeHelp} = \operatorname{fix}\ \operatorname{isPrimeHelp'}</tex> <tex>\operatorname{isPrime} = \lambda p \to \operatorname{isPrimeHelp}\ p\ \bar 2</tex> Следующее простое число. <tex>\operatorname{nextPrime';}</tex> {{---}} следующее, больше либо равное заданного, <tex>\endoperatorname{codenextPrime}</tex> {{---}}следующее, большее заданного.
<tex>\subsectionoperatorname{Проверка на простотуnextPrime''}= \lambda f \to \lambda p \to \operatorname{if}\ (\operatorname{isPrime}\ p)\ p\ (f\ (\operatorname{succ}\ p)) </tex>
<tex>\beginoperatorname{codenextPrime}isPrimeHelp' = Lam "f" $ Lam "\lambda p" $ Lam "i" $ if\to \operatorname{nextPrime'' `App` (le' `App` Var "p" `App` Var "i") `App` true' `App` ( if'' `App` (isZero' `App` (mod' `App` Var "p" `App` Var "i")) `App` false' `App` (Var "f" `App` Var "p" `App` }\ (succ' `App` Var "i")) )isPrimeHelp = fix' `App` isPrimeHelp'isPrime = Lam "p" $ isPrimeHelp `App` Var "p" `App` two'\endoperatorname{codesucc}\ p)</tex>
<tex>\beginoperatorname{codeithPrimeStep'}nextPrime'' = Lam "\lambda f" $ Lam "\to \lambda p" $ \to \lambda i \to \operatorname{if'' `App` }\ (isPrime `App` Var "p"\operatorname{isZero}\ i) `App` Var "\ p" `App` \ (Var "f" `App` \ (succ' `App` Var "\operatorname{nextPrime}\ p")) nextPrime' = fix' `App` nextPrime''nextPrime = Lam "p" $ nextPrime' `App` \ (succ' `App` Var "p")\endoperatorname{codepred}\ i))</tex>
<tex>\beginoperatorname{codeithPrime}ithPrimeStep' = Lam "f" $ Lam "p" $ Lam "\lambda i" $ if'' `App` (isZero' `App` Var "i") `App` Var "p" `App` (Var "f" `App` (nextPrime `App` Var "p") `App` (pred' `App` Var "i"))ithPrimeStep = fix' `App` ithPrimeStep'ithPrime = Lam "i" $ ithPrimeStep `App` two' `App` Var "i"\endto \operatorname{codeithPrimeStep}\ \bar 2\ i</tex>
...и всего через 314007 $<tex>\beta$</tex>-редукций вы узнаете, что третье простое число~{{---}} семь!
\subsection{Списки}