Лямбда-исчисление — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Новая страница: «{{В разработке}} \documentclass[11pt,a4paper,oneside]{article} \usepackage[english,russian]{babel} \usepackage[T2A]{fontenc} \usepackage[utf8]{inpute...»)
 
м (rollbackEdits.php mass rollback)
 
(не показано 98 промежуточных версий 19 участников)
Строка 1: Строка 1:
{{В разработке}}
+
'''Лямбда-исчисление''' (''англ. lambda calculus'') {{---}} формальная система, придуманная в 1930-х годах  
 
 
\documentclass[11pt,a4paper,oneside]{article}
 
 
 
\usepackage[english,russian]{babel}
 
\usepackage[T2A]{fontenc}
 
\usepackage[utf8]{inputenc}
 
\usepackage{graphicx}
 
\usepackage{expdlist}
 
\usepackage{mfpic}
 
\usepackage{comment}
 
\usepackage{listings}
 
\usepackage{epigraph}
 
\usepackage{url}
 
\usepackage{array}
 
%include polycode.fmt
 
%options ghci
 
%format Var v = v
 
%format App x y = x "\times" y
 
%format `App` = " \cdot "
 
%format Lam x = "\lambda" x "\to"
 
%format if' = if
 
%format then' = then
 
%format else' = else
 
%format $ = " "
 
 
 
\long\def\ignore#1{}
 
 
 
\begin{document}
 
 
 
\ignore{
 
\begin{code}
 
import Prelude hiding (id, succ, pred, and, or, catch, head, tail)
 
import qualified Prelude as P
 
\end{code}
 
}
 
 
 
\ignore{
 
\begin{code}
 
import Control.Exception
 
import Control.Monad.State
 
import qualified Data.Map as M
 
import Data.Maybe (fromMaybe)
 
 
 
type Variable = String
 
data Term = Var Variable | Lam Variable Term | App Term Term deriving (Ord)
 
 
 
instance Show Term where
 
    show (Var x) = x
 
    show (Lam x e) = "\\" ++ x ++ "." ++ show e
 
    show (App e1@(Lam _ _) e2) = "(" ++ show e1 ++ ") (" ++ show e2 ++ ")"
 
    show (App e1 (Var v)) = show e1 ++ " " ++ v
 
    show (App e1 e2) = show e1 ++ " (" ++ show e2 ++ ")"
 
 
 
free (Var v)    = [ v ]
 
free (Lam v t)  = filter (/= v) . free $ t
 
free (App t t') = (free t) ++ (free t')
 
 
 
subst :: Term -> Variable -> Term -> Term
 
subst t@(Var v)  var what = if v == var then what else t
 
subst t@(Lam v b) var what = if v == var then t else Lam v (subst b var what)
 
subst (App t t')  var what = App (subst t var what) (subst t' var what)
 
 
 
newname :: [Variable] -> Variable -> Variable
 
newname fv = P.head . filter (not . flip elem fv) . iterate ('_':)
 
 
 
deny:: [String] -> Term -> Term
 
deny d (Var v) = Var v -- Var $ newname d v
 
deny d (Lam v t) = Lam v' $ subst t v (Var v') where v' = newname (d ++ free t) v
 
deny d (App t1 t2) = App (deny d t1) (deny d t2)
 
 
 
unifyBound :: Term -> Term
 
unifyBound e = fst $ runState (unifyBound' e) (M.empty, free e)
 
 
 
unifyBound' :: Term -> State (M.Map Variable Variable, [Variable]) Term
 
unifyBound' (Var v) = do
 
    (m, used) <- get
 
    return $ Var $ fromMaybe v (M.lookup v m)
 
unifyBound' e@(App t1 t2) = do
 
    t1' <- unifyBound' t1
 
    t2' <- unifyBound' t2
 
    return $ App t1' t2'
 
unifyBound' (Lam x t) = do
 
    (m, used) <- get
 
    let new = fst $ runState unused used
 
    put (M.insert x new m, new:used)
 
    e <- unifyBound' t
 
    (_, used') <- get
 
    put (m, used')
 
    return $ Lam new e
 
 
 
eq :: Term -> Term -> Bool
 
eq (Var v) (Var v') = v == v'
 
eq (Lam v1 e1) (Lam v2 e2) = v1 == v2 && e1 `eq` e2
 
eq (App e1 e2) (App e1' e2') = e1 `eq` e1' && e2 `eq` e2'
 
eq _ _ = False
 
 
 
instance Eq Term where
 
    e1 == e2 = free e1 == free e2 && newE1 `eq` newE2 where
 
        newE1 = unifyBound e1
 
        newE2 = unifyBound e2
 
        fv = free e1
 
 
 
unused :: State [Variable] Variable
 
unused = do
 
    used <- get
 
    let new = P.head $ filter (not . (`elem` used)) $ map show [1..]
 
    put $ new:used
 
    return new
 
 
 
no :: Integer -> Term -> Term
 
 
 
no n t = no' n ({- unifyBound -} t)
 
 
 
no' 0 t = error $ "Too long sequence at [" ++ show t ++ "]"
 
no' n t
 
    | reduced = no (n - 1) rest
 
    | otherwise = t
 
    where (reduced, rest) = noOne t
 
 
 
noOne :: Term -> (Bool, Term)
 
noOne (App (Lam v t1) t2) = (True, subst (deny (free t2) t1) v t2)
 
noOne t@(Var v) = (False, t)
 
noOne (Lam v t) = (reduced, Lam v rest)
 
    where (reduced, rest) = noOne t
 
noOne t@(App t1 t2) = if reducedLeft
 
                        then (True, App t1' t2)
 
                        else if reducedRight
 
                            then (True, App t1 t2')
 
                            else (False, t)
 
    where
 
        (reducedLeft, t1') = noOne t1
 
        (reducedRight, t2') = noOne t2
 
        fv = free t2
 
 
 
sa n t = sa' n $ {- unifyBound -} t
 
 
 
sa' 0 t = error $ "Too long sequence at [" ++ show t ++ "]"
 
sa' n t
 
    | reduced = sa (n - 1) rest
 
    | otherwise = t
 
    where (reduced, rest) = saOne t
 
 
 
saOne :: Term -> (Bool, Term)
 
saOne t@(Var v) = (False, t)
 
saOne (Lam v t) = (reduced, Lam v rest)
 
    where (reduced, rest) = saOne t
 
saOne t@(App t1 t2) = if reducedRight
 
        then (True, App t1 t2')
 
        else case t1 of
 
            (Lam v t1'') -> (True, subst (deny (free t2) t1'') v t2) where
 
                (_, t1''') = saOne t1''
 
            _ -> (reducedLeft, App t1' t2)
 
    where
 
        (reducedRight, t2') = saOne t2
 
        (reducedLeft, t1') = saOne t1
 
 
 
normIO :: Int -> Term -> IO Term
 
normIO step t = do
 
    let (reduced, rest) = noOne t
 
    print $ "================" ++ " step " ++ show step ++ " ======== "
 
    if reduced
 
        then normIO (step + 1) rest
 
        else do
 
            print rest
 
            return rest
 
 
 
norm :: Term -> Term
 
norm = no 1000
 
 
 
toInt :: Term -> Int
 
toInt (Var v) = 0
 
toInt (Lam v x) = toInt x
 
toInt (App v1 v2) = (toInt v1) + (toInt v2) + 1
 
 
 
\end{code}
 
}
 
 
 
 
 
\section{Лямбда-исчисление}
 
 
 
\emph{Лямбда-исчисление}~--- формальная система, придуманная в 1930-х годах  
 
 
Алонзо Чёрчем. Лямбда-функция является, по сути, анонимной функцией.
 
Алонзо Чёрчем. Лямбда-функция является, по сути, анонимной функцией.
 
Эта концепция показала себя удобной и сейчас активно используется во многих
 
Эта концепция показала себя удобной и сейчас активно используется во многих
 
языках программирования.
 
языках программирования.
  
Более формально, \emph{лямбда-функцию} (или, \emph{лямбда-терм}) можно задать
+
== Лямбда-исчисление==
следующей грамматикой:
+
{{Определение
 
+
|definition=
$$
+
'''Лямбда-выражением''' (англ. <tex>\lambda</tex>''-term'') называется выражение, удовлетворяющее следующей грамматике:<br>
\begin{array}{r c l}
+
<tex>
\langle Term \rangle & ::= & \langle Variable \rangle \\
+
\Lambda \to V\\
                      & || & \langle Term \rangle \langle Term \rangle \\
+
\Lambda \to \Lambda \ \Lambda\\
                      & || & \lambda \langle Variable \rangle \to \langle Term \rangle\\
+
\Lambda \to \lambda V . \Lambda
                      & || & ( \langle Term \rangle )\\
+
</tex>
\langle Variable \rangle & ::= & \langle Char \rangle *\\
+
где <tex>V</tex> {{---}} множество всех строк над фиксированным алфавитом <tex> \Sigma \setminus \{ "\lambda", "\ ",\ "."\} </tex>.
\end{array}
+
}}
$$
+
Пробел во втором правиле является терминалом грамматики. Иногда его обозначают как @, чтобы он не сливался с другими символами в выражении.
  
 
В первом случае функция является просто переменной.  
 
В первом случае функция является просто переменной.  
Во втором происходит \emph{аппликация} (\emph{применение}) одной функции к другой.
+
Во втором происходит ''аппликация'' (''применение'') одной функции к другой.
 
Это аналогично вычислению функции-левого операнда на аргументе-правом операнде.
 
Это аналогично вычислению функции-левого операнда на аргументе-правом операнде.
В третьем~--- \emph{абстракция} по переменной. В данном случае происходит  
+
В третьем {{---}} ''абстракция'' по переменной. В данном случае происходит  
 
создание функции одного аргумента с заданными именем аргумента и телом функции.
 
создание функции одного аргумента с заданными именем аргумента и телом функции.
  
Рассмотрим, например, функцию |id = \x -> x|. Эта функция принимает аргумент и  
+
Рассмотрим, например, <tex>\lambda</tex>-терм <tex>\operatorname{id} = \lambda x\ .\ x</tex>. Эта функция принимает аргумент и  
 
возвращает его неизменённым. Например,  
 
возвращает его неизменённым. Например,  
|id 2 == | \eval{id 2}. Аналогично, |id y == y|.  
+
<tex>\operatorname{id}\ 2 \equiv 2</tex>. Аналогично, <tex>\operatorname{id}\ y \equiv y</tex>.  
 +
 
 +
Еще примеры:
 +
:<tex>
 +
x\\
 +
(x\ z)\\
 +
(\lambda x.(x\ z))\\
 +
(\lambda z.(\lambda w.((\lambda y.((\lambda x.(x\ z))\ y))\ w)))\\
 +
</tex>
  
Ещё один пример функции: |sum = \x -> \y -> x + y|. Эта функция двух аргументов,
+
Иногда <tex>\lambda</tex> -термы пишут по другому. Для краткости подряд идущие лямбды заменяют на одну. Например:
которая возвращает их сумму. Правда, здесь мы немного вышли за написанную выше грамматику.
+
:<tex>\lambda x\ .\ \lambda y\ .P\ \to\ \lambda xy.P</tex>
Ну да ладно. |sum 2 3 == 5|
 
  
\subsection{Приоритет операций}
+
===Приоритет операций===
\begin{itemize}
+
* Аппликация: <tex>x\ y\ z\ w \equiv ((x\ y)\ z)\ w</tex>
\item Применение левоассоциативно: |x y z w == ((x y) z) w|
+
* Абстракция забирает себе всё, до чего дотянется: <tex>\lambda x\ .\ \lambda y\ .\ \lambda z\ .\ z\ y\ x \equiv \lambda x\ .\ (\lambda y\ .\ (\lambda z\ .\ ((z\ y)\ x)))</tex>
\item Аппликация забирает себе всё, до чего дотянется:\\  
+
* Скобки играют привычную роль группировки действий
    |\x -> \y -> \z -> z y x == \x -> (\y -> (\z -> ((z y) x)))|
 
\item Скобки играют привычную роль группировки действий
 
\end{itemize}
 
  
\subsection{Свободные и связанные переменные}
+
===Свободные и связанные переменные===
\emph{Связанными} переменными называются все переменные, по которым выше в  
+
''Связанными'' переменными называются все переменные, по которым выше в  
 
дереве разбора были абстракции. Все остальные переменные называются свободными.
 
дереве разбора были абстракции. Все остальные переменные называются свободными.
  
Например, в |\x -> \y -> x|, |x| связана, а |y|~--- свободна. А в |\y -> x (\x -> x)|
+
Например, в <tex>\lambda x\ .\ y\ x</tex>, <tex>x</tex> и  связана, а <tex>y</tex>{{---}} свободна. А в <tex>\lambda y\ .\ x\ (\lambda x\ .\ x)</tex>
в своём первом вхождении переменная |x| свободна, а во втором~--- связана.
+
в своём первом вхождении переменная <tex>x</tex> свободна, а во втором {{---}} связана.
 +
 
 +
Связанные переменные {{---}} это аргументы функции. То есть для функции они являются локальными.
  
Рассмотрим функции |\y -> y| и |\x -> y|. В первой из них при взгляде на |y|
+
Рассмотрим функции <tex>\lambda y\ .\ y</tex> и <tex>\lambda x\ .\ y</tex>. В первой из них при взгляде на <tex>y</tex>
 
понятно, что она имеет отношение к переменной, по которой производилась  
 
понятно, что она имеет отношение к переменной, по которой производилась  
 
абстракция. Если по одной и той же
 
абстракция. Если по одной и той же
 
переменной абстракция производилась более одного раза, то переменная связана
 
переменной абстракция производилась более одного раза, то переменная связана
 
с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в
 
с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в
|\x -> \x -> \y -> \x -> x|, переменная |x| связана с самой правой абстракцией  
+
<tex>\lambda x\ .\ \lambda x\ .\ \lambda y\ .\ \lambda x\ .\ x</tex>, переменная <tex>x</tex> связана с самой правой абстракцией  
по |x|.
+
по <tex>x</tex>.
  
\subsection{$\alpha$-конверсия}
+
===α-эквивалентность===
  
Рассмотрим функции |(\x -> x) z| и |(\y -> y) z|. Интуитивно понятно, что они
+
{{Определение
являются одинаковыми.
+
|definition='''<tex>\alpha</tex>-эквивалентностью''' (англ. ''<tex>\alpha</tex> -equivalence'') {{---}} называется наименьшее соотношение эквивалентности на <tex>\Lambda</tex> такое что:
 +
:<tex>P=_\alpha P</tex> для любого <tex>P</tex>
 +
:<tex>\lambda x.P=_\alpha \lambda y.P[x:=y]</tex> если <tex>y \not\in FV(P)</tex>
 +
и замкнуто относительно следующих правил:
 +
:<tex> P=_\alpha P' \Rightarrow \forall x \in V: \lambda x.P=_\alpha \lambda x.P'\\
 +
P=_\alpha P' \Rightarrow \forall Z \in \Lambda : P Z =_\alpha P'Z\\
 +
P=_\alpha P' \Rightarrow \forall Z \in \Lambda : Z P =_\alpha Z P'\\
 +
P=_\alpha P' \Rightarrow P'=_\alpha P\\
 +
P=_\alpha P' \ \& \ P'=_\alpha P'' \Rightarrow P=_\alpha P''\\</tex>
 +
}}
  
\emph{$\alpha$-конверсия}~--- переименование связанной переменной. Выражение
+
Функции <tex>\lambda x\ .\ \lambda y\ .\ x\ y\ z</tex> и <tex>\lambda a\ .\ \lambda x\ .\ a\ x\ z</tex> являются <tex>\alpha</tex>-эквивалентными,
|\x -> f| можно заменить на |\y -> f[x := y]|, если |y| не входит свободно в |f|,
+
а <tex>\lambda x\ .\ \lambda y\ .\ y\ z</tex> и <tex>\lambda y\ .\ \lambda x\ .\ y\ z</tex> {{---}} нет.
где $f[x:=y]$ означает замену всех свободных вхождений $x$ в $f$ на $y$.
 
  
Функции, получающиеся одна из другой с помощью $\alpha$-конверсий, называются
+
===β-редукция===
\emph{$\alpha$-эквивалентными} и обозначаются $f \equiv_\alpha g$.
 
  
Функции |\x -> \y -> x y z| и |\a -> \x -> a x z| являются $\alpha$-эквивалентными,
+
{{Определение
а |\x -> \y -> y z| и |\y -> \x -> y z|~--- нет.
+
|definition=
 +
'''<tex>\beta</tex>-редукция''' (англ. ''<tex>\beta</tex> -reduction'') {{---}} это наименьшее соотношение на <tex>\Lambda</tex> такое что
 +
:<tex>(\lambda x.P)Q\to _\beta P[x:=Q]</tex>
 +
и замкнуто относительно следующих правил
 +
:<tex>P\to _\beta P' \Rightarrow \forall x\in V:\lambda x.P\to _\beta \lambda x.P'\\
 +
P\to _\beta P' \Rightarrow \forall Z\in \Lambda : P\ Z\to _\beta P'\ Z\\
 +
P\to _\beta P' \Rightarrow \forall Z\in \Lambda : Z\ P\to _\beta Z\ P'</tex>  
 +
}}
  
\subsection{$\beta$-редукция}
+
{{Определение
$\beta$-редукция олицетворяет идею счёта значения функции. Выражение вида
+
|definition=
|(\x -> f) y| можно заменить на $f[x := y]$, где $f[x:=y]$, как и ранее, означает
+
Через <tex>f \to_\beta g</tex> обозначают сведение <tex>f</tex> к <tex>g</tex> с помощью одной <tex>\beta</tex>-редукции.
замену всех свободных вхождений $x$ в $f$ на $y$.
+
А через <tex>f \to_\beta^* g</tex> {{---}} за ноль или более.
 +
}}
  
Через $f \to_\beta g$ обозначают сведение $f$ к $g$ с помощью одной $\beta$-редукции.
+
В <tex>\beta</tex>-редукции вполне возможна функция вида <tex>\lambda x. \lambda x.x</tex>. Во время подстановки вместо <tex>x</tex> внутренняя переменная не заменяется - действует принцип локальной переменной. Но принято считать, что таких ситуаций не возникает и все переменные называются разными именами.
А через $f \to_\beta^* g$~--- за ноль или более.
 
  
\subsection{$\eta$-редукция}
+
===Каррирование===
Рассмотрим выражение вида |\x -> f x|. Если подставить в эту функцию значение
 
$y$, то получим: $(\lambda x \to f x) y \to_\beta f y$. Но если просто подставить
 
$y$ в $f$, то получится то же самое.
 
  
$\eta$-редукция~--- преобразование |\x -> f x| в $f$.
+
{{Определение
 +
|definition=
 +
'''Каррирование''' (англ. ''carrying'') {{---}} преобразование функции от многих переменных в функцию, берущую свои аргументы по одному. Для функции <tex>h</tex> типа <tex>h\ :\ (A\ *\ B)\ \to\ C</tex> оператор каррирования <tex>\Lambda </tex> выполняет преобразование <tex>\Lambda (h)\ :\ A\to (B\to C)</tex>. Таким образом <tex>\Lambda (h)</tex> берет аргумент типа <tex>A</tex> и возвращает функцию типа <tex>B\ \to\ C</tex>. С интуитивной точки зрения, каррирование функции позволяет фиксировать ее некоторый аргумент, возвращая функцию от остальных аргументов. Таким образом, <tex>\Lambda</tex> представляет собой функцию типа <tex>\Lambda :\ (A\ *\ B\to C)\to (A\to (B\to C))</tex>.
 +
}}
  
\section{Нотация Де Брюина}
+
==Нотация Де Брауна==
Существует также альтернативное эквивалентное определение $\lambda$-исчисления.
+
Существует также альтернативное эквивалентное определение <tex>\lambda</tex>-исчисления.
 
В оригинальном определении для обозначения переменных использовались имена,
 
В оригинальном определении для обозначения переменных использовались имена,
 
и была проблема с тем, что не были запрещены одинаковые имена в разных
 
и была проблема с тем, что не были запрещены одинаковые имена в разных
Строка 272: Строка 111:
  
 
От этой проблемы можно избавиться следующим образом. Вместо имени переменной  
 
От этой проблемы можно избавиться следующим образом. Вместо имени переменной  
будет храниться натуральное число~--- количество абстракций в дереве разбора,
+
будет храниться натуральное число {{---}} количество абстракций в дереве разбора,
 
на которое нужно подняться, чтобы найти ту лямбду, с которой данная переменная  
 
на которое нужно подняться, чтобы найти ту лямбду, с которой данная переменная  
 
связана. В данной нотации получаются несколько более простые определения  
 
связана. В данной нотации получаются несколько более простые определения  
свободных переменных и $\beta$-редукции.  
+
свободных переменных и <tex>\beta</tex>-редукции.
 +
 
 +
Грамматику нотации можно задать как:
 +
:<tex>e\ ::= n\ |\ \lambda .e\ |\ e\ e</tex>
 +
 
 +
Примеры выражений в этой нотации:
 +
 
 +
{|
 +
! Standart
 +
! de Bruijn
 +
|-
 +
| $\lambda x.x$
 +
| $\lambda .0$
 +
|-
 +
| $\lambda z.z$
 +
| $\lambda .0$
 +
|-
 +
| $\lambda x. \lambda y.x$
 +
| $\lambda . \lambda .1$
 +
|-
 +
| $\lambda x. \lambda y. \lambda s. \lambda z.x\ s\ (y\ s\ z)$
 +
| $\lambda . \lambda . \lambda . \lambda .3\ 1(2\ 1\ 0)$
 +
|-
 +
| $(\lambda x.x\ x)(\lambda x.x\ x)$
 +
| $(\lambda .0\ 0)(\lambda .0\ 0)$
 +
|-
 +
| $(\lambda x. \lambda x.x)(\lambda y.y)$
 +
| $(\lambda .\lambda .0)(\lambda .0)$
 +
|}
  
 
Переменная называется свободной, если ей соответствует число, которое больше
 
Переменная называется свободной, если ей соответствует число, которое больше
 
количества абстракций на пути до неё в дереве разбора.
 
количества абстракций на пути до неё в дереве разбора.
  
При $\beta$-редукции же нужно будет ко всем свободным переменным заменяющего  
+
При <tex>\beta</tex>-редукции же нужно будет ко всем свободным переменным заменяющего  
 
дерева при каждой замене прибавить число, равное разницы уровней раньше и сейчас.
 
дерева при каждой замене прибавить число, равное разницы уровней раньше и сейчас.
Это будет соответствовать тому, что эта переменная продолжит <<держаться>> за
+
Это будет соответствовать тому, что эта переменная продолжит «держаться» за
 
ту же лямбду, что и раньше.
 
ту же лямбду, что и раньше.
  
\section{Нумералы Чёрча}
+
==Нумералы Чёрча и программирование на <tex>\lambda</tex>-исчислении==
  
\subsection{Определение}
+
===Определение===
 
Введём на основе лямбда-исчисления аналог натуральных чисел, основанный на идее,  
 
Введём на основе лямбда-исчисления аналог натуральных чисел, основанный на идее,  
что натуральное число~--- это или ноль, или увеличенное на единицу натуральное  
+
что натуральное число {{---}} это или ноль, или увеличенное на единицу натуральное  
 
число.
 
число.
  
\begin{code}
+
:<tex>\bar 0 = \lambda s\ .\ \lambda z\ .\ z</tex>
zero' = Lam "s" $ Lam "z" $ Var "z"
+
:<tex>\bar 1 = \lambda s\ .\ \lambda z\ .\ s\ z</tex>
one' = Lam "s" $ Lam "z" $ Var "s" `App` Var "z"
+
:<tex>\bar 2 = \lambda s\ .\ \lambda z\ .\ s\ (s\ z)</tex>
two' = Lam "s" $ Lam "z" $ Var "s" `App` (Var "s" `App` Var "z")
+
:<tex>\bar 3 = \lambda s\ .\ \lambda z\ .\ s\ (s\ (s\ z))</tex>
three' = Lam "s" $ Lam "z" $ Var "s" `App` (Var "s" `App` (Var "s" `App` Var "z"))
 
\end{code}
 
  
 
Каждое число будет функцией двух аргументов: какой-то функции и начального значения.
 
Каждое число будет функцией двух аргументов: какой-то функции и начального значения.
Число $n$ будет $n$ раз применять функцию к начальному значению и возвращать  
+
Число <tex>n</tex> будет <tex>n</tex> раз применять функцию к начальному значению и возвращать  
результат. Если такому <<числу>> дать на вход функцию $(+1)$ и $0$ в качестве  
+
результат. Если такому "числу" дать на вход функцию <tex>(+1)</tex> и <tex>0</tex> в качестве  
 
начального значения, то на выходе как раз будет ожидаемое от функции число:
 
начального значения, то на выходе как раз будет ожидаемое от функции число:
|three (+1) 0 == | \eval{three (+1) 0}.
+
<tex>\bar 3\ (+1)\ 0 \equiv 3</tex>.
  
\subsection{+1}
+
===+1===
Функция, прибавляющая 1 к числу, должна принимать первым аргументом число.
+
Функция, прибавляющая <tex>1</tex> к числу, должна принимать первым аргументом число.
Но число~--- функция двух аргументов. Значит, эта функция должна принимать три
+
Но число {{---}} функция двух аргументов. Значит, эта функция должна принимать три
аргумента: <<число>> $n$, которое хочется увеличить, функция, которую надо будет
+
аргумента: "число" <tex>n</tex>, которое хочется увеличить, функция, которую надо будет
$n+1$ раз применить, и начальное значение.
+
<tex>n+1</tex> раз применить, и начальное значение.
  
\begin{code}
+
<tex>\operatorname{succ} = \lambda n\ .\ \lambda s\ .\ \lambda z\ .\ s\ (n\ s\ z)</tex>
succ' = Lam "n" $ Lam "s" $ Lam "z" $ Var "s" `App` (Var "n" `App` Var "s" `App` Var "z")
 
\end{code}
 
  
Здесь $n s z$~--- $n$ раз применённая к $z$ функция $s$. Но нужно применить $n+1$
+
Здесь <tex>n\ s\ z</tex> {{---}} <tex>n</tex> раз применённая к <tex>z</tex> функция <tex>s</tex>. Но нужно применить <tex>n+1</tex>
раз. Отсюда $s (n s z)$.
+
раз. Отсюда <tex>s\ (n\ s\ z)</tex>.
  
\subsection{Сложение}
+
===Сложение===
Сложение двух чисел похоже на прибавление единицы. Но только надо прибавить не
+
Сложение двух чисел похоже на прибавление единицы. Но только надо прибавить не единицу, а второе число.
единицу, а второе число.
 
  
\begin{code}
+
<tex>\operatorname{plus} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ n\ s\ (m\ s\ z)</tex>
plus' = Lam "n" $ Lam "m" $ Lam "s" $ Lam "z" $ Var "n" `App` Var "s" `App` (Var "m" `App` Var "s" `App` Var "z")
 
\end{code}
 
  
<<$n$ раз применить $s$ к применённому $m$ раз $s$ к $z$>>
+
<tex>n</tex> раз применить <tex>s</tex> к применённому <tex>m</tex> раз <tex>s</tex> к <tex>z</tex>
  
|(plus three three) (+1) 0 == | \eval{(plus three three) (+1) 0}
+
<tex>(\operatorname{plus}\ \bar 3\ \bar 3)\ (+1)\ 0 \equiv 6</tex>
  
\subsection{Умножение}
+
<tex>(\operatorname{plus}\ ((\operatorname{plus}\ 2\ 5)(+1)\ 0)\ 4)(+1)0 \equiv 11</tex>
 +
 
 +
===Умножение===
 
Умножение похоже на сложение, но прибавлять надо не единицу, а второе число.
 
Умножение похоже на сложение, но прибавлять надо не единицу, а второе число.
 
Или, в терминах нумералов Чёрча, в качестве применяемой несколько раз
 
Или, в терминах нумералов Чёрча, в качестве применяемой несколько раз
функции должна быть не $s$, а функция, применяющая $n$ раз $s$.
+
функции должна быть не <tex>s</tex>, а функция, применяющая <tex>n</tex> раз <tex>s</tex>.
  
\begin{code}
+
<tex>\operatorname{mult} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ n\ (m\ s)\ z</tex>
mult' = Lam "n" $ Lam "m" $ Lam "s" $ Var "n" `App` (Var "m" `App` Var "s")
 
\end{code}
 
  
Здесь |m s|~--- функция, которая $m$ раз применит $s$ к тому, что дадут ей на  
+
Здесь <tex>m\ s</tex> {{---}} функция, которая <tex>m</tex> раз применит <tex>s</tex> к тому, что дадут ей на  
вход. С помощью $\eta$-редукции можно немного сократить эту формулу
+
вход. С помощью <tex>\eta</tex>-редукции можно немного сократить эту формулу
  
\begin{spec}
+
<tex>\operatorname{mult} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ n\ (m\ s)</tex>
mult = \n -> \m -> \s -> n (m s)
 
\end{spec}
 
  
|(mult three three) (+1) 0 == | \eval{(mult three three) (+1) 0}
+
<tex>(\operatorname{mult} \bar 3\ \bar 3)\ (+1)\ 0 \equiv 9</tex>
  
\subsection{Возведение в степень}
+
===Возведение в степень===
 
It's a kind of magic
 
It's a kind of magic
  
\begin{code}
+
<tex>\operatorname{power} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ m\ n\ s\ z</tex>
power' = Lam "n" $ Lam "m" $ Var "m" `App` Var "n"
 
\end{code}
 
  
|(power three (succ three)) (+1) 0 == | \eval{(power three (succ three)) (+1) 0}
+
<tex>(\operatorname{power}\ \bar 3\ (\operatorname{succ}\ \bar 3))\ (+1)\ 0 \equiv 81</tex>
  
\subsection{Логические значения}
+
===Логические значения===
\begin{code}
+
<tex>\operatorname{true} = \lambda a\ .\ \lambda b\ .\ a</tex>
true' = Lam "a" $ Lam "b" $ Var "a"
+
 
false' = Lam "a" $ Lam "b" $ Var "b"
+
<tex>\operatorname{false} = \lambda a\ .\ \lambda b\ .\ b</tex>
\end{code}
 
  
 
Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы.
 
Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы.
Забавный факт: $false \equiv_\alpha zero$. Эти функции сделаны такими для того,  
+
Забавный факт: <tex>\operatorname{false} \equiv_\alpha \operatorname{zero}</tex>. Эти функции сделаны такими для того,  
чтобы красиво написать функцию $if$:
+
чтобы красиво написать функцию <tex>\operatorname{if}</tex>:
  
\begin{code}
+
<tex>\operatorname{if} = \lambda p\ .\ \lambda t\ .\ \lambda e\ .\ p\ t\ e</tex>
if'' = Lam "p" $ Lam "t" $ Lam "e" $ Var "p" `App` Var "t" `App` Var "e"
 
\end{code}
 
  
Если ей в качестве первого аргумента дадут $true$, то вернётся $t$, иначе~--- $e$.
+
Если ей в качестве первого аргумента дадут <tex>\operatorname{true}</tex>, то вернётся <tex>t</tex>, иначе {{---}} <tex>e</tex>.
  
 
Стандартные функции булевой логики:
 
Стандартные функции булевой логики:
  
\begin{code}
+
<tex>\operatorname{and} = \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ n\ m\ \operatorname{false}</tex>
and' = Lam "n" $ Lam "m" $ if'' `App` Var "n" `App` Var "m" `App` false'
+
 
or' = Lam "n" $ Lam "m" $ if'' `App` Var "n" `App` true' `App` Var "m"
+
<tex>\operatorname{or} = \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ n\ \operatorname{true} \  m</tex>
not' = Lam "b" $ if'' `App` Var "b" `App` false' `App` true'
+
 
\end{code}
+
<tex>\operatorname{not} = \lambda b\ .\ \operatorname{if}\ b\ \operatorname{false} \ \operatorname{true}</tex>
  
 
Ещё одной важной функцией является функция проверки, является ли число нулём:
 
Ещё одной важной функцией является функция проверки, является ли число нулём:
  
\begin{code}
+
<tex>\operatorname{isZero} = \lambda n\ .\ n\ (\lambda c\ .\ \operatorname{false})\ \operatorname{true}</tex>
isZero' = Lam "n" $ Var "n" `App` (Lam "c" false') `App` true'
 
\end{code}
 
  
Функция выглядит несколько странно. |\c -> false|~--- функция, которая независимо
+
Функция выглядит несколько странно. <tex>\lambda c \to \operatorname{false}</tex> - функция, которая независимо
от того, что ей дали на вход, возвращает $false$. Тогда, если в качестве $n$
+
от того, что ей дали на вход, возвращает <tex>\operatorname{false}</tex>. Тогда, если в качестве <tex>n</tex>
 
будет дан ноль, то функция, по определению нуля, не выполнится ни разу, и будет
 
будет дан ноль, то функция, по определению нуля, не выполнится ни разу, и будет
возвращено значение по умолчанию $true$. Иначе же функция будет запущено, и  
+
возвращено значение по умолчанию <tex>\operatorname{true}</tex>. Иначе же функция будет запущено, и  
вернётся $false$.
+
вернётся <tex>\operatorname{false}</tex>.
  
\subsection{Пара}
+
===Пара===
  
\begin{code}
+
<tex>\operatorname{pair} = \lambda a\ .\ \lambda b\ .\ \lambda t\ .\ t\ a\ b</tex>
pair' = Lam "a" $ Lam "b" $ Lam "t" $ Var "t" `App` Var "a" `App` Var "b"
 
fst'' = Lam "p" $ Var "p" `App` true'
 
snd'' = Lam "p" $ Var "p" `App` false'
 
\end{code}
 
  
Функция $pair$ принимает два значения и запаковывает их в пару так, чтобы к
+
<tex>\operatorname{fst} = \lambda p\ .\ p\ \operatorname{true}</tex>
ним можно было обращаться по $fst$ и $snd$. В $fst$ и $snd$ вместо $t$ в $pair$
 
будет подставлено $true$ или $false$, возвращающие, соответственно, первый и
 
второй аргументы, то есть $a$ или $b$, соответственно.
 
  
\subsection{Вычитание}
+
<tex>\operatorname{snd} = \lambda p\ .\ p\ \operatorname{false}</tex>
В отличие от всех предыдущих функций, вычитание для натуральных чисел определено
 
только в случае, если уменьшаемое больше вычитаемого. Положим в противном случае
 
результат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу.
 
Тогда на её основе легко сделать, собственно, вычитание.
 
  
\begin{code}
+
Функция <tex>\operatorname{pair}</tex> принимает два значения и запаковывает их в пару так, чтобы к ним можно было обращаться по <tex>\operatorname{fst}</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>, соответственно.
minus' = Lam "n" $ Lam "m" $ Var "m" `App` pred' `App` Var "n"
 
\end{code}
 
  
<<$m$ раз вычесть единицу из $n$>>.
+
===Вычитание===
 +
В отличие от всех предыдущих функций, вычитание для натуральных чисел определено только в случае, если уменьшаемое больше вычитаемого. Положим в противном случае результат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу. Тогда на её основе легко сделать, собственно, вычитание.
  
Осталось, собственно, функция для вычитания единицы. Однако, это не так просто,
+
<tex>\operatorname{minus} = \lambda n\ .\ \lambda m\ .\ m\ \operatorname{pred} n</tex>
как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую
 
нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет
 
проблематично. Если попробовать воспользоваться идеей о том, чтобы, начав от
 
нуля, идти вперёд, и пройти на один шаг меньше, то будет не очень понятно, как
 
же остановиться ровно за один шаг до конца. Для реализации вычитания единицы
 
сделаем следующее. $n$ раз выполним следующее: имея пару $(n-1, n-2)$ построим пару
 
$(n, n-1)$. Тогда после $n$ шагов во втором элементе пары будет записано число
 
$n-1$, которое и хочется получить.
 
% --pred = \n -> \s -> \z -> n (\g -> \h -> h (g s)) (\u -> z) (\u->u)
 
% --pred = \n -> \s -> \z -> snd (n (\p -> (pair (s (fst p)) (fst p))) (pair z z))
 
% --pred = \n -> \s -> \z -> fst' (n (\p -> pair (s (fst p))(fst p)) (pair z z))
 
  
\begin{code}
+
Это то же самое, что <tex>m</tex> раз вычесть единицу из <tex>n</tex>.
pred' = Lam "n" $
 
        Lam "s" $
 
        Lam "z" $
 
            snd'' `App` (Var "n"
 
                            `App` (
 
                                    Lam "p" $ pair'
 
                                        `App` (Var "s" `App` (fst'' `App` Var "p"))
 
                                        `App` (fst'' `App` Var "p")
 
                                  )
 
                            `App` ( pair' `App` Var "z" `App` Var "z" )
 
                        )
 
\end{code}
 
  
Если вы ничего не поняли, не огорчайтесь. Вычитание придумал Клини, когда
+
Осталось, собственно, функция для вычитания единицы. Однако, это не так просто, как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет проблематично. Если попробовать воспользоваться идеей о том, чтобы, начав от нуля, идти вперёд, и пройти на один шаг меньше, то будет не очень понятно, как же остановиться ровно за один шаг до конца. Для реализации вычитания единицы сделаем следующее. <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>, которое и хочется получить.  
ему вырывали зуб мудрости. А сейчас наркоз уже не тот!
 
  
\subsection{Сравнение}
+
<tex>\operatorname{pred} = \lambda n\ .\ \lambda s\ .\ \lambda z.\ \operatorname{snd}\ (
Так как вычитание определено таким способом, чтобы для случая, в котором
+
  n\ (
уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить
+
          \lambda p\ .\ \operatorname{pair}\ (s\ (\operatorname{fst} p))\ (\operatorname{fst} p)
сравнение на больше-меньше через него. Равными же числа $a$ и $b$ считаются,
+
    )\ (\operatorname{pair}\ z\ z))</tex>
если $a - b = 0 \wedge b - a = 0$.
 
  
\begin{code}
+
Если вы ничего не поняли, не огорчайтесь. Вычитание придумал Клини, когда ему вырывали зуб мудрости. А сейчас наркоз уже не тот.
le' = Lam "n" $ Lam "m" $ isZero' `App` (minus' `App` Var "n" `App` Var "m")
 
less' = Lam "n" $ Lam "m" $ le' `App` Var "n" `App` (pred' `App` Var "m")
 
eq' = Lam "n" $ Lam "m" $ and'
 
            `App` (isZero' `App` (minus' `App` Var "n" `App` Var "m"))
 
            `App` (isZero' `App` (minus' `App` Var "m" `App` Var "n"))
 
\end{code}
 
  
\subsection{Комбинатор неподвижной точки}
+
===Сравнение===
Попробуем выразить в лямбда-исчислении какую-нибудь рекурсивную функцию.
+
Так как вычитание определено таким способом, чтобы для случая, в котором уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить сравнение на больше-меньше через него. Равными же числа <tex>a</tex> и <tex>b</tex> считаются, если <tex>a - b = 0 \wedge b - a = 0</tex>.
Напрмер, факториал.
 
  
\begin{spec}
+
<tex>\operatorname{le} = \lambda n\ .\ \lambda m\ .\ \operatorname{isZero}\ (\operatorname{minus}\ n\ m)</tex>
fact = \x -> if (isZero x) one (fact (pred x))
 
\end{spec}
 
  
Мы столкнулись с проблемой. В определении функции $fact$ используется функция
+
<tex>\operatorname{less} = \lambda n\ .\ \lambda m\ .\ \operatorname{le}\ n\ (\operatorname{pred} m)</tex>
$fact$. При формальной замене, получим бесконечную функцию. Можно попытаться решить
 
эту проблему следующим образом
 
  
\begin{spec}
+
<tex>\operatorname{eq} = \lambda n\ .\ \lambda m\ .\ \operatorname{and}\ (\operatorname{isZero}\ (\operatorname{minus}\ n\ m))\
fact = (\f -> \x -> if (isZero x) one (f (pred x))) fact
+
(\operatorname{isZero}\ (\operatorname{minus}\ m\ n))</tex>
\end{spec}
 
  
\emph{Неподвижной точкой} лямбда-функции $f$ назовём такую функцию $x$, что
+
===Комбинатор неподвижной точки===
$f x \to_\beta x$. Лямбда исчисление обладаем замечательным свойством: у каждой
+
Попробуем выразить в лямбда-исчислении какую-нибудь функцию, использующую рекурсию. Например, факториал.
функции есть неподвижная точка!
 
  
Рассмотрим такую функцию.  
+
<tex>\operatorname{fact} = \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{fact}\ (\operatorname{pred}\ x))</tex>
  
\begin{code}
+
Мы столкнулись с проблемой. В определении функции <tex>\operatorname{fact}</tex> используется функция <tex>\operatorname{fact}</tex>. При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом
fix' = Lam "f" $  (Lam "x" $ Var "f" `App` (Var "x" `App` Var "x"))
 
            `App`  (Lam "x" $ Var "f" `App` (Var "x" `App` Var "x"))
 
\end{code}
 
  
Заметим, что $fix' \to_\beta \lambda f \to f ((\lambda x \to f (x x)) (\lambda x \to f (x x)))$.
+
<tex>\operatorname{fact} = (\lambda f\ .\ \lambda x\ .\ \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\ .\ (\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x))</tex>
 +
 
 +
Заметим, что <tex>\operatorname{fix} \to_\beta^* \lambda f\ .\ f\ ((\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)))</tex>.
 
Или, что то же самое,  
 
Или, что то же самое,  
$\lambda f \to (\lambda x \to f (x x)) (\lambda x \to f (x x)) \to_\beta
+
<tex>\lambda f\ .\ (\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)) \to_\beta^*</tex>
\lambda f \to f ((\lambda x \to f (x x)) (\lambda x \to f (x x)))$
+
<tex>\lambda f\ .\ f\ ((\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)))</tex>
  
 
Рассмотрим функцию
 
Рассмотрим функцию
  
\begin{code}
+
<tex>\operatorname{fact'} = \lambda f\ .\ \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{mult}\ x\ (f\ (\operatorname{pred}\ x)))</tex>
fact'' = Lam "f" $ Lam "x" $ if'' `App` (isZero' `App` Var "x")  
+
 
                                  `App` one'
+
Как было показано выше, <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> {{---}} искомая функция, считающая факториал.
                                  `App` (mult' `App` Var "x" `App` (Var "f" `App`
 
                                            (pred' `App` Var "x")))
 
\end{code}
 
  
Как было показано выше, $fix f \to_\beta f (fix f)$, то есть,
+
<tex>\operatorname{fact} = \operatorname{fix}\ \operatorname{fact'}</tex>
$fix fact'' \to_\beta fact'$, где $fact'$~--- искомая функция, считающая факториал.
 
  
\begin{code}
+
Это даст функцию, которая посчитает факториал числа. Но делать она это будет мееедленно-меееедленно. Для того, чтобы посчитать <tex>5!</tex> потребовалось сделать 66066 <tex>\beta</tex>-редукций.
fact' = fix' `App` fact''
 
\end{code}
 
  
Это даст функцию, которая посчитает факториал числа. Но делать она это будет
+
Наиболее известным комбинатором неподвижной точки является <tex>Y</tex>-комбинатор, введенный известным американским ученым Хаскеллом Карри как
мееедленно-меееедленно. Для того, чтобы посчитать $5!$ потребовалось сделать
+
:<tex>Y\ = \ \lambda f.(\lambda x.f(x\ x))\ (\lambda x.f(x\ x))</tex>
66066 $\beta$-редукций.
 
  
Тут правда ничего не понятно? :'(
+
===Деление===
 +
Воспользовавшись идеей о том, что можно делать рекурсивные функции, сделаем функцию, которая будет искать частное двух чисел.
  
\subsection{Деление}
+
<tex>\operatorname{div'} = \lambda div\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ \bar 0\ (\operatorname{succ}\ (div\ (\operatorname{minus}\ n\ m)\ m))</tex>
Воспользовавшись идеей о том, что можно делать рекурсивные функции, сделаем
 
функцию, которая будет искать частное двух чисел.
 
  
\begin{code}
+
<tex>\operatorname{div} = \operatorname{fix}\ \operatorname{div'}</tex>
div'' = Lam "div" $ Lam "n" $ Lam "m" $ if'' `App` (less' `App` Var "n" `App` Var "m")
 
        `App` zero'
 
        `App` (succ' `App` (Var "div" `App` (minus' `App` Var "n" `App` Var "m") `App` Var "m"))
 
div' = fix' `App` div''
 
\end{code}
 
  
 
И остатка от деления
 
И остатка от деления
  
\begin{code}
+
<tex>\operatorname{mod'} = \lambda mod\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ n\ (mod\ (\operatorname{minus}\ n\ m)\ m)</tex>
mod'' = Lam "mod" $ Lam "n" $ Lam "m" $ if'' `App` (less' `App` Var "n" `App` Var "m")
+
 
        `App` Var "n"
+
<tex>\operatorname{mod} = \operatorname{fix}\ \operatorname{mod'}</tex>
        `App` (Var "mod" `App` (minus' `App` Var "n" `App` Var "m") `App` Var "m")
+
 
mod' = fix' `App` mod'';
+
===Проверка на простоту===
\end{code}
+
 
 +
<tex>\operatorname{isPrimeHelp}</tex> {{---}} принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от <tex>2</tex> до <tex>p-1</tex>. Если на что-нибудь разделилось, то число {{---}} составное, иначе {{---}} простое.
 +
 
 +
<tex>\operatorname{isPrimeHelp'} =</tex><tex>\lambda f\ .\ \lambda p\ .\ \lambda i\ .\ \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\ .\ \operatorname{isPrimeHelp}\ p\ \bar 2</tex>
 +
 
 +
Следующее простое число. <tex>\operatorname{nextPrime'}</tex> {{---}} следующее, больше либо равное заданного, <tex>\operatorname{nextPrime}</tex> {{---}} следующее, большее заданного.
  
\subsection{Проверка на простоту}
+
<tex>\operatorname{nextPrime''} = \lambda f\ .\ \lambda p\ .\ \operatorname{if}\ (\operatorname{isPrime}\ p)\ p\ (f\ (\operatorname{succ}\ p)) </tex>
  
$isPrimeHelp$~--- принимает число, которое требуется проверить на простоту и
+
<tex>\operatorname{nextPrime'} = \operatorname{fix}\ \operatorname{nextPrime'}</tex>
то, на что его надо попытаться поделить, перебирая это от 2 до $p-1$. Если на
 
что-нибудь разделилось, то число~--- составное, иначе~--- простое.
 
  
\begin{code}
+
<tex>\operatorname{nextPrime} = \lambda p\ .\ \operatorname{nextPrime'}\ (\operatorname{succ}\ p)</tex>
isPrimeHelp' = Lam "f" $ Lam "p" $ Lam "i" $ if'' `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'
 
\end{code}
 
  
Следующее простое число. $nextPrime'$~--- следующее, больше либо равное заданного,
+
<tex>\operatorname{ithPrimeStep}</tex> пропрыгает <tex>i</tex> простых чисел вперёд. <tex>\operatorname{ithPrime}</tex> принимает число <tex>i</tex> и пропрыгивает столько простых чисел вперёд, начиная с двойки.
$nextPrime$~--- следующее, большее заданного.
 
  
\begin{code}
+
<tex>\operatorname{ithPrimeStep'} = \lambda f\ .\ \lambda p\ .\ \lambda i\ .\ \operatorname{if}\ (\operatorname{isZero}\ i)\ p\ (f(\operatorname{nextPrime}\ p)\ (\operatorname{pred}\ i))</tex>
nextPrime'' = Lam "f" $ Lam "p" $ if'' `App` (isPrime `App` Var "p")
 
                                  `App` Var "p"
 
                                  `App` (Var "f" `App` (succ' `App` Var "p"))
 
nextPrime' = fix' `App` nextPrime''
 
nextPrime = Lam "p" $ nextPrime' `App` (succ' `App` Var "p")
 
\end{code}
 
  
$ithPrimeStep$ пропрыгает $i$ простых чисел вперёд. $ithPrime$ принимает число
+
<tex>\operatorname{ithPrimeStep} = \operatorname{fix}\ \operatorname{ithPrimeStep'}</tex>
$i$ и пропрыгивает столько простых чисел вперёд, начиная с двойки.
 
  
\begin{code}
+
<tex>\operatorname{ithPrime} = \lambda i\ .\ \operatorname{ithPrimeStep}\ \bar 2\ i</tex>
ithPrimeStep' = Lam "f" $ Lam "p" $ Lam "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"
 
\end{code}
 
  
...и всего через 314007 $\beta$-редукций вы узнаете, что третье простое число~---
+
...и всего через 314007 <tex>\beta</tex>-редукций вы узнаете, что третье простое число {{---}} семь!
семь!
 
  
\subsection{Списки}
+
===Списки===
  
 
Для работы со списками чисел нам понадобятся следующие функции:
 
Для работы со списками чисел нам понадобятся следующие функции:
\begin{itemize}
+
* <tex>\operatorname{empty}</tex> {{---}} возвращает пустой список
    \item $empty$~--- возвращает пустой список
+
* <tex>\operatorname{cons}</tex> {{---}} принимает первый элемент и оставшийся список, склеивает их
    \item $cons$~--- принимает первый элемент и оставшийся список, склеивает их
+
* <tex>\operatorname{head}</tex> {{---}} вернуть голову списка
    \item $head$~--- вернуть голову списка
+
* <tex>\operatorname{tail}</tex> {{---}} вернуть хвост списка
    \item $tail$~--- вернуть хвост списка
+
 
\end{itemize}
+
Список будем хранить в следующем виде: <tex>\langle len, p_1^{a_1}p_2^{a_2}\ldots p_{len}^{a_{len}} \rangle</tex>. При этом, голова списка будет храниться как показатель степени при <tex>p_{len}</tex>.
 +
 
 +
<tex>\operatorname{empty} = \operatorname{pair}\ \operatorname{zero}\ \bar 1</tex>
 +
 
 +
<tex>\operatorname{cons} = \lambda h\ .\ \lambda t\ .\ \operatorname{pair}\ (\operatorname{succ}\ (\operatorname{fst}\ t))\ (\operatorname{mult}\ (\operatorname{snd}\ t)\ (\operatorname{power}\ (\operatorname{ithPrime}\ (\operatorname{fst}\ t))\ h))</tex>
 +
 
 +
<tex>\operatorname{head} = \lambda list\ .\ \operatorname{getExponent}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list)))</tex>
 +
 
 +
<tex>\operatorname{tail} = \lambda list\ .\ \operatorname{pair}\ (\operatorname{pred}\ (\operatorname{fst}\ list))
 +
(\operatorname{eliminateMultiplier}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list))))</tex>
  
Список будем хранить в следующем виде: $\langle len, p_1^{a_1}p_2^{a_2}\ldots p_{len}^{a_{len}} \rangle$. При этом, голова списка будет храниться как показатель степени при $p_{len}$.
+
<tex>\operatorname{eliminateMultiplier'} =</tex><tex> \lambda f\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ n\ m))\ (f\ (\operatorname{div}\ n\ m)\ m)\ n</tex>
  
\begin{code}
+
<tex>\operatorname{eliminateMultiplier} = \operatorname{fix}\ \operatorname{eliminateMultiplier'}</tex>
empty = pair' `App` zero' `App` one'
 
cons = Lam "h" $ Lam "t" $ pair' `App` (succ' `App` (fst'' `App` Var "t"))
 
        `App` (mult' `App` (snd'' `App` Var "t") `App` (power'
 
                `App` (ithPrime `App` (fst'' `App` Var "t"))
 
                `App` Var "h"
 
        ))
 
head = Lam "list" $ getExponent `App` (snd'' `App` Var "list")
 
                                `App` (ithPrime `App` (pred' `App` (fst'' `App` Var "list")))
 
  
tail = Lam "list" $ pair' `App` (pred' `App` (fst'' `App` Var "list"))
+
<tex>\operatorname{getExponent'} =</tex><tex> \lambda f\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ n\ m))\ (\operatorname{succ}\ (f\ (\operatorname{div}\ n\ m)\ m))\ \bar 0</tex>
                          `App` (eliminateMultiplier `App` (snd'' `App` Var "list")
 
                                  `App` (ithPrime `App` (pred' `App` (fst'' `App` Var "list" )))
 
                                )
 
  
eliminateMultiplier' = Lam "f" $ Lam "n" $ Lam "m" $ if'' `App` (isZero' `App` (mod' `App` Var "n" `App` Var "m"))
+
<tex>\operatorname{getExponent} = \operatorname{fix}\ \operatorname{getExponent'}</tex>
                        `App` (Var "f" `App` (div' `App` Var "n" `App` Var "m") `App` Var "m")
 
                        `App` Var "n"
 
eliminateMultiplier = fix' `App` eliminateMultiplier'
 
  
getExponent' = Lam "f" $ Lam "n" $ Lam "m" $ if'' `App` (isZero' `App` (mod' `App` Var "n" `App` Var "m"))
+
==Выводы==
                `App` (succ' `App`(Var "f" `App` (div' `App` Var "n" `App` Var "m") `App` Var "m"))
 
                `App` zero'
 
getExponent = fix' `App` getExponent'
 
\end{code}
 
  
На основе этого всего уже можно реализовать эмулятор машины тьюринга:
+
На основе этого всего уже можно реализовать эмулятор машины тьюринга: с помощью пар, списков чисел можно хранить состояния. С помощью рекурсии можно обрабатывать переходы. Входная строка будет даваться, например, закодированной аналогично списку: пара из длины и числа, характеризующего список степенями простых. Я бы продолжил это писать, но уже на операции <tex>\operatorname{head} [1, 2]</tex> я не дождался окончания выполнения. Скорость лямбда-исчисления как вычислителя печальна.
с помощью пар, списков чисел можно хранить состояния. С помощью рекурсии можно
 
обрабатывать переходы. Входная строка будет даваться, например, закодированной
 
аналогично списку: пара из длины и числа, характеризующего список степенями  
 
простых. Я бы продолжил это писать, но уже на операции $head [1, 2]$ я не  
 
дождался окончания выполнения. Скорость лямбда-исчисления как вычислителя
 
печальна.
 
  
\ignore{
+
==Примеры (слабонервным не смотреть)==
\begin{code}
 
  
four' = norm $ succ' `App` three'
+
====fact====
five' = norm $ succ' `App` four'
+
<tex>(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda x.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> (x))</tex><tex> (\lambda s.\lambda z.s z)</tex><tex> ((\lambda n.\lambda m.\lambda s.n (m s))</tex><tex> (x)</tex><tex> (f ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex>((\lambda a.\lambda b.\lambda t.t a b)</tex><tex>(z)</tex><tex> z))) (x)))))</tex>
 +
====head====
 +
<tex>\lambda list.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n(\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (n)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (m)))</tex><tex> (n)</tex><tex> m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m) m)) n m)) ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (f ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda div.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (n)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (m)))</tex><tex> (n)</tex><tex> m) (\lambda s.\lambda z.z)</tex><tex> ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (div ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m) m))) n m) m)) (\lambda s.\lambda z.z))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (list))</tex><tex> ((\lambda i.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> (i))</tex><tex> p (f ((\lambda p.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda p.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda p.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (p)</tex><tex> i) (\lambda a.\lambda b.a)</tex><tex> ((\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (n)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (m)))</tex><tex> (n)</tex><tex> m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m) m)) p i)) (\lambda a.\lambda b.b)</tex><tex> (f p ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (i)))))</tex><tex> p (\lambda s.\lambda z.s (s z)))</tex><tex> (p))</tex><tex> p (f ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (p))))</tex><tex> ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (p)))</tex><tex> (p))</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (i))))</tex><tex> (\lambda s.\lambda z.s (s z))</tex><tex> i) ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (list))))</tex>
  
list2 = norm $ cons `App` one' `App` empty
 
list32 = cons `App` zero' `App` list2
 
  
normFiveFact = normIO 0 $ fact' `App` five'
+
====tail====
 +
<tex>\lambda list.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (list)))</tex><tex> ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (n)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (m)))</tex><tex> (n)</tex><tex> m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m) m)) n m)) (f ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda div.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (n)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (m)))</tex><tex> (n)</tex><tex> m) (\lambda s.\lambda z.z)</tex><tex> ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (div ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m) m))) n m) m) n) ((\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (list))</tex><tex> ((\lambda i.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> (i))</tex><tex> p (f ((\lambda p.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda p.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda p.(\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (p)</tex><tex> i) (\lambda a.\lambda b.a)</tex><tex> ((\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda f.(\lambda x.f (x x))</tex><tex> (\lambda x.f (x x)))</tex><tex> (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)</tex><tex> ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)</tex><tex> (\lambda a.\lambda b.a))</tex><tex> ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m)) (n)</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (m)))</tex><tex> (n)</tex><tex> m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) n) (n)</tex><tex> m) m)) p i)) (\lambda a.\lambda b.b)</tex><tex> (f p ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (i)))))</tex><tex> p (\lambda s.\lambda z.s (s z)))</tex><tex> (p))</tex><tex> p (f ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (p))))</tex><tex> ((\lambda n.\lambda s.\lambda z.s (n s z))</tex><tex> (p)))</tex><tex> (p))</tex><tex> ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) (i))))</tex><tex> (\lambda s.\lambda z.s (s z))</tex><tex> i) ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))</tex><tex> (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (s ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (p)))</tex><tex> ((\lambda a.\lambda b.\lambda t.t a b)</tex><tex> (z)</tex><tex> z))) ((\lambda p.p (\lambda a.\lambda b.a))</tex><tex> (list)))))</tex>
  
-- fiftysix = mult twentyeight two
+
== См. также ==
-- fiftyfive = pred fiftysix
+
*[[Неразрешимость задачи вывода типов в языке с зависимыми типами]]
-- six = pred seven
 
  
--main = do print $ fiftysix (+1) 0
+
==Источники информации==
main = do
+
* Lectures on the Curry Howard - Isomorphism
--  f <- normIO 0 $ ithPrime `App` three'
+
*[https://github.com/shd/tt2014 Д. Штукенберг. Лекции]
--  f <- normIO 0 $ getExponent `App` (norm $ plus' `App` four' `App` four') `App` two'
+
*[http://en.wikipedia.org/wiki/Lambda-calculus Английская Википедия]
    f <- normIO 0 $ head `App` (tail `App` list32)
+
*[http://ru.wikipedia.org/wiki/%D0%9B%D1%8F%D0%BC%D0%B1%D0%B4%D0%B0-%D0%B8%D1%81%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5 Русская Википедия]
    print $ toInt f
+
*[http://worrydream.com/AlligatorEggs Игра про крокодилов]
\end{code}
 
}
 
  
\end{document}
+
[[Категория: Теория формальных языков]]
[http://rain.ifmo.ru/~komarov/Turing.lhs]
+
[[Категория: Теория вычислимости]]

Текущая версия на 19:42, 4 сентября 2022

Лямбда-исчисление (англ. lambda calculus) — формальная система, придуманная в 1930-х годах Алонзо Чёрчем. Лямбда-функция является, по сути, анонимной функцией. Эта концепция показала себя удобной и сейчас активно используется во многих языках программирования.

Лямбда-исчисление

Определение:
Лямбда-выражением (англ. [math]\lambda[/math]-term) называется выражение, удовлетворяющее следующей грамматике:

[math] \Lambda \to V\\ \Lambda \to \Lambda \ \Lambda\\ \Lambda \to \lambda V . \Lambda [/math]

где [math]V[/math] — множество всех строк над фиксированным алфавитом [math] \Sigma \setminus \{ "\lambda", "\ ",\ "."\} [/math].

Пробел во втором правиле является терминалом грамматики. Иногда его обозначают как @, чтобы он не сливался с другими символами в выражении.

В первом случае функция является просто переменной. Во втором происходит аппликация (применение) одной функции к другой. Это аналогично вычислению функции-левого операнда на аргументе-правом операнде. В третьем — абстракция по переменной. В данном случае происходит создание функции одного аргумента с заданными именем аргумента и телом функции.

Рассмотрим, например, [math]\lambda[/math]-терм [math]\operatorname{id} = \lambda x\ .\ x[/math]. Эта функция принимает аргумент и возвращает его неизменённым. Например, [math]\operatorname{id}\ 2 \equiv 2[/math]. Аналогично, [math]\operatorname{id}\ y \equiv y[/math].

Еще примеры:

[math] x\\ (x\ z)\\ (\lambda x.(x\ z))\\ (\lambda z.(\lambda w.((\lambda y.((\lambda x.(x\ z))\ y))\ w)))\\ [/math]

Иногда [math]\lambda[/math] -термы пишут по другому. Для краткости подряд идущие лямбды заменяют на одну. Например:

[math]\lambda x\ .\ \lambda y\ .P\ \to\ \lambda xy.P[/math]

Приоритет операций

  • Аппликация: [math]x\ y\ z\ w \equiv ((x\ y)\ z)\ w[/math]
  • Абстракция забирает себе всё, до чего дотянется: [math]\lambda x\ .\ \lambda y\ .\ \lambda z\ .\ z\ y\ x \equiv \lambda x\ .\ (\lambda y\ .\ (\lambda z\ .\ ((z\ y)\ x)))[/math]
  • Скобки играют привычную роль группировки действий

Свободные и связанные переменные

Связанными переменными называются все переменные, по которым выше в дереве разбора были абстракции. Все остальные переменные называются свободными.

Например, в [math]\lambda x\ .\ y\ x[/math], [math]x[/math] и связана, а [math]y[/math]— свободна. А в [math]\lambda y\ .\ x\ (\lambda x\ .\ x)[/math] в своём первом вхождении переменная [math]x[/math] свободна, а во втором — связана.

Связанные переменные — это аргументы функции. То есть для функции они являются локальными.

Рассмотрим функции [math]\lambda y\ .\ y[/math] и [math]\lambda x\ .\ y[/math]. В первой из них при взгляде на [math]y[/math] понятно, что она имеет отношение к переменной, по которой производилась абстракция. Если по одной и той же переменной абстракция производилась более одного раза, то переменная связана с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в [math]\lambda x\ .\ \lambda x\ .\ \lambda y\ .\ \lambda x\ .\ x[/math], переменная [math]x[/math] связана с самой правой абстракцией по [math]x[/math].

α-эквивалентность

Определение:
[math]\alpha[/math]-эквивалентностью (англ. [math]\alpha[/math] -equivalence) — называется наименьшее соотношение эквивалентности на [math]\Lambda[/math] такое что:
[math]P=_\alpha P[/math] для любого [math]P[/math]
[math]\lambda x.P=_\alpha \lambda y.P[x:=y][/math] если [math]y \not\in FV(P)[/math]

и замкнуто относительно следующих правил:

[math] P=_\alpha P' \Rightarrow \forall x \in V: \lambda x.P=_\alpha \lambda x.P'\\ P=_\alpha P' \Rightarrow \forall Z \in \Lambda : P Z =_\alpha P'Z\\ P=_\alpha P' \Rightarrow \forall Z \in \Lambda : Z P =_\alpha Z P'\\ P=_\alpha P' \Rightarrow P'=_\alpha P\\ P=_\alpha P' \ \& \ P'=_\alpha P'' \Rightarrow P=_\alpha P''\\[/math]


Функции [math]\lambda x\ .\ \lambda y\ .\ x\ y\ z[/math] и [math]\lambda a\ .\ \lambda x\ .\ a\ x\ z[/math] являются [math]\alpha[/math]-эквивалентными, а [math]\lambda x\ .\ \lambda y\ .\ y\ z[/math] и [math]\lambda y\ .\ \lambda x\ .\ y\ z[/math] — нет.

β-редукция

Определение:
[math]\beta[/math]-редукция (англ. [math]\beta[/math] -reduction) — это наименьшее соотношение на [math]\Lambda[/math] такое что
[math](\lambda x.P)Q\to _\beta P[x:=Q][/math]

и замкнуто относительно следующих правил

[math]P\to _\beta P' \Rightarrow \forall x\in V:\lambda x.P\to _\beta \lambda x.P'\\ P\to _\beta P' \Rightarrow \forall Z\in \Lambda : P\ Z\to _\beta P'\ Z\\ P\to _\beta P' \Rightarrow \forall Z\in \Lambda : Z\ P\to _\beta Z\ P'[/math]


Определение:
Через [math]f \to_\beta g[/math] обозначают сведение [math]f[/math] к [math]g[/math] с помощью одной [math]\beta[/math]-редукции. А через [math]f \to_\beta^* g[/math] — за ноль или более.


В [math]\beta[/math]-редукции вполне возможна функция вида [math]\lambda x. \lambda x.x[/math]. Во время подстановки вместо [math]x[/math] внутренняя переменная не заменяется - действует принцип локальной переменной. Но принято считать, что таких ситуаций не возникает и все переменные называются разными именами.

Каррирование

Определение:
Каррирование (англ. carrying) — преобразование функции от многих переменных в функцию, берущую свои аргументы по одному. Для функции [math]h[/math] типа [math]h\ :\ (A\ *\ B)\ \to\ C[/math] оператор каррирования [math]\Lambda [/math] выполняет преобразование [math]\Lambda (h)\ :\ A\to (B\to C)[/math]. Таким образом [math]\Lambda (h)[/math] берет аргумент типа [math]A[/math] и возвращает функцию типа [math]B\ \to\ C[/math]. С интуитивной точки зрения, каррирование функции позволяет фиксировать ее некоторый аргумент, возвращая функцию от остальных аргументов. Таким образом, [math]\Lambda[/math] представляет собой функцию типа [math]\Lambda :\ (A\ *\ B\to C)\to (A\to (B\to C))[/math].


Нотация Де Брауна

Существует также альтернативное эквивалентное определение [math]\lambda[/math]-исчисления. В оригинальном определении для обозначения переменных использовались имена, и была проблема с тем, что не были запрещены одинаковые имена в разных абстракциях.

От этой проблемы можно избавиться следующим образом. Вместо имени переменной будет храниться натуральное число — количество абстракций в дереве разбора, на которое нужно подняться, чтобы найти ту лямбду, с которой данная переменная связана. В данной нотации получаются несколько более простые определения свободных переменных и [math]\beta[/math]-редукции.

Грамматику нотации можно задать как:

[math]e\ ::= n\ |\ \lambda .e\ |\ e\ e[/math]

Примеры выражений в этой нотации:

Standart de Bruijn
$\lambda x.x$ $\lambda .0$
$\lambda z.z$ $\lambda .0$
$\lambda x. \lambda y.x$ $\lambda . \lambda .1$
$\lambda x. \lambda y. \lambda s. \lambda z.x\ s\ (y\ s\ z)$ $\lambda . \lambda . \lambda . \lambda .3\ 1(2\ 1\ 0)$
$(\lambda x.x\ x)(\lambda x.x\ x)$ $(\lambda .0\ 0)(\lambda .0\ 0)$
$(\lambda x. \lambda x.x)(\lambda y.y)$ $(\lambda .\lambda .0)(\lambda .0)$

Переменная называется свободной, если ей соответствует число, которое больше количества абстракций на пути до неё в дереве разбора.

При [math]\beta[/math]-редукции же нужно будет ко всем свободным переменным заменяющего дерева при каждой замене прибавить число, равное разницы уровней раньше и сейчас. Это будет соответствовать тому, что эта переменная продолжит «держаться» за ту же лямбду, что и раньше.

Нумералы Чёрча и программирование на [math]\lambda[/math]-исчислении

Определение

Введём на основе лямбда-исчисления аналог натуральных чисел, основанный на идее, что натуральное число — это или ноль, или увеличенное на единицу натуральное число.

[math]\bar 0 = \lambda s\ .\ \lambda z\ .\ z[/math]
[math]\bar 1 = \lambda s\ .\ \lambda z\ .\ s\ z[/math]
[math]\bar 2 = \lambda s\ .\ \lambda z\ .\ s\ (s\ z)[/math]
[math]\bar 3 = \lambda s\ .\ \lambda z\ .\ s\ (s\ (s\ z))[/math]

Каждое число будет функцией двух аргументов: какой-то функции и начального значения. Число [math]n[/math] будет [math]n[/math] раз применять функцию к начальному значению и возвращать результат. Если такому "числу" дать на вход функцию [math](+1)[/math] и [math]0[/math] в качестве начального значения, то на выходе как раз будет ожидаемое от функции число: [math]\bar 3\ (+1)\ 0 \equiv 3[/math].

+1

Функция, прибавляющая [math]1[/math] к числу, должна принимать первым аргументом число. Но число — функция двух аргументов. Значит, эта функция должна принимать три аргумента: "число" [math]n[/math], которое хочется увеличить, функция, которую надо будет [math]n+1[/math] раз применить, и начальное значение.

[math]\operatorname{succ} = \lambda n\ .\ \lambda s\ .\ \lambda z\ .\ s\ (n\ s\ z)[/math]

Здесь [math]n\ s\ z[/math][math]n[/math] раз применённая к [math]z[/math] функция [math]s[/math]. Но нужно применить [math]n+1[/math] раз. Отсюда [math]s\ (n\ s\ z)[/math].

Сложение

Сложение двух чисел похоже на прибавление единицы. Но только надо прибавить не единицу, а второе число.

[math]\operatorname{plus} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ n\ s\ (m\ s\ z)[/math]

[math]n[/math] раз применить [math]s[/math] к применённому [math]m[/math] раз [math]s[/math] к [math]z[/math]

[math](\operatorname{plus}\ \bar 3\ \bar 3)\ (+1)\ 0 \equiv 6[/math]

[math](\operatorname{plus}\ ((\operatorname{plus}\ 2\ 5)(+1)\ 0)\ 4)(+1)0 \equiv 11[/math]

Умножение

Умножение похоже на сложение, но прибавлять надо не единицу, а второе число. Или, в терминах нумералов Чёрча, в качестве применяемой несколько раз функции должна быть не [math]s[/math], а функция, применяющая [math]n[/math] раз [math]s[/math].

[math]\operatorname{mult} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ n\ (m\ s)\ z[/math]

Здесь [math]m\ s[/math] — функция, которая [math]m[/math] раз применит [math]s[/math] к тому, что дадут ей на вход. С помощью [math]\eta[/math]-редукции можно немного сократить эту формулу

[math]\operatorname{mult} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ n\ (m\ s)[/math]

[math](\operatorname{mult} \bar 3\ \bar 3)\ (+1)\ 0 \equiv 9[/math]

Возведение в степень

It's a kind of magic

[math]\operatorname{power} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ m\ n\ s\ z[/math]

[math](\operatorname{power}\ \bar 3\ (\operatorname{succ}\ \bar 3))\ (+1)\ 0 \equiv 81[/math]

Логические значения

[math]\operatorname{true} = \lambda a\ .\ \lambda b\ .\ a[/math]

[math]\operatorname{false} = \lambda a\ .\ \lambda b\ .\ b[/math]

Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы. Забавный факт: [math]\operatorname{false} \equiv_\alpha \operatorname{zero}[/math]. Эти функции сделаны такими для того, чтобы красиво написать функцию [math]\operatorname{if}[/math]:

[math]\operatorname{if} = \lambda p\ .\ \lambda t\ .\ \lambda e\ .\ p\ t\ e[/math]

Если ей в качестве первого аргумента дадут [math]\operatorname{true}[/math], то вернётся [math]t[/math], иначе — [math]e[/math].

Стандартные функции булевой логики:

[math]\operatorname{and} = \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ n\ m\ \operatorname{false}[/math]

[math]\operatorname{or} = \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ n\ \operatorname{true} \ m[/math]

[math]\operatorname{not} = \lambda b\ .\ \operatorname{if}\ b\ \operatorname{false} \ \operatorname{true}[/math]

Ещё одной важной функцией является функция проверки, является ли число нулём:

[math]\operatorname{isZero} = \lambda n\ .\ n\ (\lambda c\ .\ \operatorname{false})\ \operatorname{true}[/math]

Функция выглядит несколько странно. [math]\lambda c \to \operatorname{false}[/math] - функция, которая независимо от того, что ей дали на вход, возвращает [math]\operatorname{false}[/math]. Тогда, если в качестве [math]n[/math] будет дан ноль, то функция, по определению нуля, не выполнится ни разу, и будет возвращено значение по умолчанию [math]\operatorname{true}[/math]. Иначе же функция будет запущено, и вернётся [math]\operatorname{false}[/math].

Пара

[math]\operatorname{pair} = \lambda a\ .\ \lambda b\ .\ \lambda t\ .\ t\ a\ b[/math]

[math]\operatorname{fst} = \lambda p\ .\ p\ \operatorname{true}[/math]

[math]\operatorname{snd} = \lambda p\ .\ p\ \operatorname{false}[/math]

Функция [math]\operatorname{pair}[/math] принимает два значения и запаковывает их в пару так, чтобы к ним можно было обращаться по [math]\operatorname{fst}[/math] и [math]\operatorname{snd}[/math]. В [math]\operatorname{fst}[/math] и [math]\operatorname{snd}[/math] вместо [math]t[/math] в [math]\operatorname{pair}[/math] будет подставлено [math]\operatorname{true}[/math] или [math]\operatorname{false}[/math], возвращающие, соответственно, первый и второй аргументы, то есть [math]a[/math] или [math]b[/math], соответственно.

Вычитание

В отличие от всех предыдущих функций, вычитание для натуральных чисел определено только в случае, если уменьшаемое больше вычитаемого. Положим в противном случае результат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу. Тогда на её основе легко сделать, собственно, вычитание.

[math]\operatorname{minus} = \lambda n\ .\ \lambda m\ .\ m\ \operatorname{pred} n[/math]

Это то же самое, что [math]m[/math] раз вычесть единицу из [math]n[/math].

Осталось, собственно, функция для вычитания единицы. Однако, это не так просто, как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет проблематично. Если попробовать воспользоваться идеей о том, чтобы, начав от нуля, идти вперёд, и пройти на один шаг меньше, то будет не очень понятно, как же остановиться ровно за один шаг до конца. Для реализации вычитания единицы сделаем следующее. [math]n[/math] раз выполним следующее: имея пару [math]\langle n-1, n-2\rangle[/math] построим пару [math]\langle n, n-1\rangle[/math]. Тогда после [math]n[/math] шагов во втором элементе пары будет записано число [math]n-1[/math], которое и хочется получить.

[math]\operatorname{pred} = \lambda n\ .\ \lambda s\ .\ \lambda z.\ \operatorname{snd}\ ( n\ ( \lambda p\ .\ \operatorname{pair}\ (s\ (\operatorname{fst} p))\ (\operatorname{fst} p) )\ (\operatorname{pair}\ z\ z))[/math]

Если вы ничего не поняли, не огорчайтесь. Вычитание придумал Клини, когда ему вырывали зуб мудрости. А сейчас наркоз уже не тот.

Сравнение

Так как вычитание определено таким способом, чтобы для случая, в котором уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить сравнение на больше-меньше через него. Равными же числа [math]a[/math] и [math]b[/math] считаются, если [math]a - b = 0 \wedge b - a = 0[/math].

[math]\operatorname{le} = \lambda n\ .\ \lambda m\ .\ \operatorname{isZero}\ (\operatorname{minus}\ n\ m)[/math]

[math]\operatorname{less} = \lambda n\ .\ \lambda m\ .\ \operatorname{le}\ n\ (\operatorname{pred} m)[/math]

[math]\operatorname{eq} = \lambda n\ .\ \lambda m\ .\ \operatorname{and}\ (\operatorname{isZero}\ (\operatorname{minus}\ n\ m))\ (\operatorname{isZero}\ (\operatorname{minus}\ m\ n))[/math]

Комбинатор неподвижной точки

Попробуем выразить в лямбда-исчислении какую-нибудь функцию, использующую рекурсию. Например, факториал.

[math]\operatorname{fact} = \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{fact}\ (\operatorname{pred}\ x))[/math]

Мы столкнулись с проблемой. В определении функции [math]\operatorname{fact}[/math] используется функция [math]\operatorname{fact}[/math]. При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом

[math]\operatorname{fact} = (\lambda f\ .\ \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (f\ (\operatorname{pred}\ x)))\ \operatorname{fact}[/math]


Определение:
Неподвижной точкой лямбда-функции [math]f[/math] назовём такую функцию [math]x[/math], что [math]f\ x \to_\beta^* x[/math].


Лямбда исчисление обладаем замечательным свойством: у каждой функции есть неподвижная точка!

Рассмотрим следующую функцию.

[math]\operatorname{fix} = \lambda f\ .\ (\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x))[/math]

Заметим, что [math]\operatorname{fix} \to_\beta^* \lambda f\ .\ f\ ((\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)))[/math]. Или, что то же самое, [math]\lambda f\ .\ (\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)) \to_\beta^*[/math] [math]\lambda f\ .\ f\ ((\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)))[/math]

Рассмотрим функцию

[math]\operatorname{fact'} = \lambda f\ .\ \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{mult}\ x\ (f\ (\operatorname{pred}\ x)))[/math]

Как было показано выше, [math]\operatorname{fix} f \to_\beta^* f\ (\operatorname{fix} f)[/math], то есть, [math]\operatorname{fix}\ \operatorname{fact'} \to_\beta^* \operatorname{fact}[/math], где [math]\operatorname{fact}[/math] — искомая функция, считающая факториал.

[math]\operatorname{fact} = \operatorname{fix}\ \operatorname{fact'}[/math]

Это даст функцию, которая посчитает факториал числа. Но делать она это будет мееедленно-меееедленно. Для того, чтобы посчитать [math]5![/math] потребовалось сделать 66066 [math]\beta[/math]-редукций.

Наиболее известным комбинатором неподвижной точки является [math]Y[/math]-комбинатор, введенный известным американским ученым Хаскеллом Карри как

[math]Y\ = \ \lambda f.(\lambda x.f(x\ x))\ (\lambda x.f(x\ x))[/math]

Деление

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

[math]\operatorname{div'} = \lambda div\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ \bar 0\ (\operatorname{succ}\ (div\ (\operatorname{minus}\ n\ m)\ m))[/math]

[math]\operatorname{div} = \operatorname{fix}\ \operatorname{div'}[/math]

И остатка от деления

[math]\operatorname{mod'} = \lambda mod\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ n\ (mod\ (\operatorname{minus}\ n\ m)\ m)[/math]

[math]\operatorname{mod} = \operatorname{fix}\ \operatorname{mod'}[/math]

Проверка на простоту

[math]\operatorname{isPrimeHelp}[/math] — принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от [math]2[/math] до [math]p-1[/math]. Если на что-нибудь разделилось, то число — составное, иначе — простое.

[math]\operatorname{isPrimeHelp'} =[/math][math]\lambda f\ .\ \lambda p\ .\ \lambda i\ .\ \operatorname{if}\ (\operatorname{le}\ p\ i)\ \operatorname{true}\ (\operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ p\ i))\ \operatorname{false}\ (f\ p\ (\operatorname{succ}\ i)))[/math]

[math]\operatorname{isPrimeHelp} = \operatorname{fix}\ \operatorname{isPrimeHelp'}[/math]

[math]\operatorname{isPrime} = \lambda p\ .\ \operatorname{isPrimeHelp}\ p\ \bar 2[/math]

Следующее простое число. [math]\operatorname{nextPrime'}[/math] — следующее, больше либо равное заданного, [math]\operatorname{nextPrime}[/math] — следующее, большее заданного.

[math]\operatorname{nextPrime''} = \lambda f\ .\ \lambda p\ .\ \operatorname{if}\ (\operatorname{isPrime}\ p)\ p\ (f\ (\operatorname{succ}\ p)) [/math]

[math]\operatorname{nextPrime'} = \operatorname{fix}\ \operatorname{nextPrime'}[/math]

[math]\operatorname{nextPrime} = \lambda p\ .\ \operatorname{nextPrime'}\ (\operatorname{succ}\ p)[/math]

[math]\operatorname{ithPrimeStep}[/math] пропрыгает [math]i[/math] простых чисел вперёд. [math]\operatorname{ithPrime}[/math] принимает число [math]i[/math] и пропрыгивает столько простых чисел вперёд, начиная с двойки.

[math]\operatorname{ithPrimeStep'} = \lambda f\ .\ \lambda p\ .\ \lambda i\ .\ \operatorname{if}\ (\operatorname{isZero}\ i)\ p\ (f\ (\operatorname{nextPrime}\ p)\ (\operatorname{pred}\ i))[/math]

[math]\operatorname{ithPrimeStep} = \operatorname{fix}\ \operatorname{ithPrimeStep'}[/math]

[math]\operatorname{ithPrime} = \lambda i\ .\ \operatorname{ithPrimeStep}\ \bar 2\ i[/math]

...и всего через 314007 [math]\beta[/math]-редукций вы узнаете, что третье простое число — семь!

Списки

Для работы со списками чисел нам понадобятся следующие функции:

  • [math]\operatorname{empty}[/math] — возвращает пустой список
  • [math]\operatorname{cons}[/math] — принимает первый элемент и оставшийся список, склеивает их
  • [math]\operatorname{head}[/math] — вернуть голову списка
  • [math]\operatorname{tail}[/math] — вернуть хвост списка

Список будем хранить в следующем виде: [math]\langle len, p_1^{a_1}p_2^{a_2}\ldots p_{len}^{a_{len}} \rangle[/math]. При этом, голова списка будет храниться как показатель степени при [math]p_{len}[/math].

[math]\operatorname{empty} = \operatorname{pair}\ \operatorname{zero}\ \bar 1[/math]

[math]\operatorname{cons} = \lambda h\ .\ \lambda t\ .\ \operatorname{pair}\ (\operatorname{succ}\ (\operatorname{fst}\ t))\ (\operatorname{mult}\ (\operatorname{snd}\ t)\ (\operatorname{power}\ (\operatorname{ithPrime}\ (\operatorname{fst}\ t))\ h))[/math]

[math]\operatorname{head} = \lambda list\ .\ \operatorname{getExponent}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list)))[/math]

[math]\operatorname{tail} = \lambda list\ .\ \operatorname{pair}\ (\operatorname{pred}\ (\operatorname{fst}\ list)) (\operatorname{eliminateMultiplier}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list))))[/math]

[math]\operatorname{eliminateMultiplier'} =[/math][math] \lambda f\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ n\ m))\ (f\ (\operatorname{div}\ n\ m)\ m)\ n[/math]

[math]\operatorname{eliminateMultiplier} = \operatorname{fix}\ \operatorname{eliminateMultiplier'}[/math]

[math]\operatorname{getExponent'} =[/math][math] \lambda f\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ n\ m))\ (\operatorname{succ}\ (f\ (\operatorname{div}\ n\ m)\ m))\ \bar 0[/math]

[math]\operatorname{getExponent} = \operatorname{fix}\ \operatorname{getExponent'}[/math]

Выводы

На основе этого всего уже можно реализовать эмулятор машины тьюринга: с помощью пар, списков чисел можно хранить состояния. С помощью рекурсии можно обрабатывать переходы. Входная строка будет даваться, например, закодированной аналогично списку: пара из длины и числа, характеризующего список степенями простых. Я бы продолжил это писать, но уже на операции [math]\operatorname{head} [1, 2][/math] я не дождался окончания выполнения. Скорость лямбда-исчисления как вычислителя печальна.

Примеры (слабонервным не смотреть)

fact

[math](\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda x.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] (x))[/math][math] (\lambda s.\lambda z.s z)[/math][math] ((\lambda n.\lambda m.\lambda s.n (m s))[/math][math] (x)[/math][math] (f ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math]((\lambda a.\lambda b.\lambda t.t a b)[/math][math](z)[/math][math] z))) (x)))))[/math]

head

[math]\lambda list.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n(\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (n)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (m)))[/math][math] (n)[/math][math] m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m) m)) n m)) ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (f ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda div.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (n)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (m)))[/math][math] (n)[/math][math] m) (\lambda s.\lambda z.z)[/math][math] ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (div ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m) m))) n m) m)) (\lambda s.\lambda z.z))[/math][math] ((\lambda p.p (\lambda a.\lambda b.b))[/math][math] (list))[/math][math] ((\lambda i.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] (i))[/math][math] p (f ((\lambda p.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda p.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda p.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (p)[/math][math] i) (\lambda a.\lambda b.a)[/math][math] ((\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (n)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (m)))[/math][math] (n)[/math][math] m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m) m)) p i)) (\lambda a.\lambda b.b)[/math][math] (f p ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (i)))))[/math][math] p (\lambda s.\lambda z.s (s z)))[/math][math] (p))[/math][math] p (f ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (p))))[/math][math] ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (p)))[/math][math] (p))[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (i))))[/math][math] (\lambda s.\lambda z.s (s z))[/math][math] i) ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (list))))[/math]


tail

[math]\lambda list.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (list)))[/math][math] ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (n)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (m)))[/math][math] (n)[/math][math] m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m) m)) n m)) (f ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda div.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (n)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (m)))[/math][math] (n)[/math][math] m) (\lambda s.\lambda z.z)[/math][math] ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (div ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m) m))) n m) m) n) ((\lambda p.p (\lambda a.\lambda b.b))[/math][math] (list))[/math][math] ((\lambda i.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] (i))[/math][math] p (f ((\lambda p.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda p.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda p.(\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda f.\lambda p.\lambda i.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (p)[/math][math] i) (\lambda a.\lambda b.a)[/math][math] ((\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda f.(\lambda x.f (x x))[/math][math] (\lambda x.f (x x)))[/math][math] (\lambda mod.\lambda n.\lambda m.(\lambda p.\lambda t.\lambda e.p t e)[/math][math] ((\lambda n.\lambda m.(\lambda n.\lambda m.(\lambda n.n (\lambda c.\lambda a.\lambda b.b)[/math][math] (\lambda a.\lambda b.a))[/math][math] ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m)) (n)[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (m)))[/math][math] (n)[/math][math] m) n (mod ((\lambda n.\lambda m.m (\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) n) (n)[/math][math] m) m)) p i)) (\lambda a.\lambda b.b)[/math][math] (f p ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (i)))))[/math][math] p (\lambda s.\lambda z.s (s z)))[/math][math] (p))[/math][math] p (f ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (p))))[/math][math] ((\lambda n.\lambda s.\lambda z.s (n s z))[/math][math] (p)))[/math][math] (p))[/math][math] ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) (i))))[/math][math] (\lambda s.\lambda z.s (s z))[/math][math] i) ((\lambda n.\lambda s.\lambda z.(\lambda p.p (\lambda a.\lambda b.b))[/math][math] (n (\lambda p.(\lambda a.\lambda b.\lambda t.t a b)[/math][math] (s ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (p)))[/math][math] ((\lambda a.\lambda b.\lambda t.t a b)[/math][math] (z)[/math][math] z))) ((\lambda p.p (\lambda a.\lambda b.a))[/math][math] (list)))))[/math]

См. также

Источники информации