Advanced handouts
Add missing file Co-authored-by: Mark <mark@betalupi.com> Co-committed-by: Mark <mark@betalupi.com>
This commit is contained in:
110
src/Advanced/Lambda Calculus/main.tex
Executable file
110
src/Advanced/Lambda Calculus/main.tex
Executable file
@ -0,0 +1,110 @@
|
||||
% use [nosolutions] flag to hide solutions.
|
||||
% use [solutions] flag to show solutions.
|
||||
\documentclass[
|
||||
solutions,
|
||||
singlenumbering
|
||||
]{../../../lib/tex/ormc_handout}
|
||||
\usepackage{../../../lib/tex/macros}
|
||||
|
||||
|
||||
\usepackage{mathtools} % for \coloneqq
|
||||
|
||||
% An invisible marker, used to
|
||||
% draw arrows in equations.
|
||||
\newcommand{\tzmr}[1]{
|
||||
\tikz[
|
||||
overlay,
|
||||
remember picture,
|
||||
right = 0.25ex
|
||||
] \node (#1) {};
|
||||
}
|
||||
\newcommand{\tzm}[1]{
|
||||
\tikz[
|
||||
overlay,
|
||||
remember picture
|
||||
] \node (#1) {};
|
||||
}
|
||||
|
||||
\newcommand{\lm}{\lambda}
|
||||
|
||||
|
||||
|
||||
% TODO:
|
||||
% Lazy evaluation (alternate Y)
|
||||
% Add a few theorems
|
||||
% Better ending -> applications?
|
||||
% - nix, comparison to imperative
|
||||
|
||||
|
||||
|
||||
\uptitlel{Advanced 2}
|
||||
\uptitler{\smallurl{}}
|
||||
\title{Lambda Calculus}
|
||||
\subtitle{Prepared by Mark on \today{}}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
\hfill
|
||||
\begin{minipage}{8cm}
|
||||
Beware of the Turing tar pit, in which everything is possible but nothing of interest is easy.
|
||||
|
||||
\vspace{2ex}
|
||||
|
||||
Alan Perlis, \textit{Epigrams of Programming}, \#54
|
||||
\end{minipage}
|
||||
\hfill\null
|
||||
|
||||
\vspace{4mm}
|
||||
|
||||
\makeatletter
|
||||
\if@solutions
|
||||
\begin{instructornote}
|
||||
\textbf{Context \& Computability:} (or, why do we need lambda calculus?)\par
|
||||
\note{From Peter Selinger's \textit{Lecture Notes on Lambda Calculus}}
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
In the 1930s, several people were interested in the question: what does it mean for
|
||||
a function $f : \mathbb{N} \mapsto \mathbb{N}$ to be computable? An informal definition of computability
|
||||
is that there should be a pencil-and-paper method allowing a trained person to
|
||||
calculate $f(n)$, for any given $n$. The concept of a pencil-and-paper method is not
|
||||
so easy to formalize. Three different researchers attempted to do so, resulting in
|
||||
the following definitions of computability:
|
||||
|
||||
\begin{itemize}
|
||||
\item Turing defined an idealized computer we now call a Turing machine, and
|
||||
postulated that a function is \say{computable} if and only
|
||||
if it can be computed by such a machine.
|
||||
|
||||
\item G\"odel defined the class of general recursive functions as the smallest set of
|
||||
functions containing all the constant functions, the successor function, and
|
||||
closed under certain operations (such as compositions and recursion). He
|
||||
postulated that a function is \say{computable} if and only
|
||||
if it is general recursive.
|
||||
|
||||
\item Church defined an idealized programming language called the lambda calculus,
|
||||
and postulated that a function is \say{computable} if and only if it can be written as a lambda term.
|
||||
\end{itemize}
|
||||
|
||||
It was proved by Church, Kleene, Rosser, and Turing that all three computational
|
||||
models were equivalent to each other --- each model defines the same class
|
||||
of computable functions. Whether or not they are equivalent to the \say{intuitive}
|
||||
notion of computability is a question that cannot be answered, because there is no
|
||||
formal definition of \say{intuitive computability.} The assertion that they are in fact
|
||||
equivalent to intuitive computility is known as the Church-Turing thesis.
|
||||
\end{instructornote}
|
||||
\vfill
|
||||
\pagebreak
|
||||
\fi
|
||||
\makeatother
|
||||
|
||||
\input{parts/00 intro}
|
||||
\input{parts/01 combinators}
|
||||
\input{parts/02 boolean}
|
||||
\input{parts/03 numbers}
|
||||
\input{parts/04 recursion}
|
||||
\input{parts/05 challenges}
|
||||
|
||||
\end{document}
|
6
src/Advanced/Lambda Calculus/meta.toml
Normal file
6
src/Advanced/Lambda Calculus/meta.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[metadata]
|
||||
title = "Lambda Calculus"
|
||||
|
||||
[publish]
|
||||
handout = true
|
||||
solutions = true
|
461
src/Advanced/Lambda Calculus/parts/00 intro.tex
Executable file
461
src/Advanced/Lambda Calculus/parts/00 intro.tex
Executable file
@ -0,0 +1,461 @@
|
||||
\section{Introduction}
|
||||
\textit{Lambda calculus} is a model of computation, much like the Turing machine.
|
||||
As we're about to see, it works in a fundamentally different way, which has a few
|
||||
practical applications we'll discuss at the end of class.
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
|
||||
A lambda function starts with a lambda ($\lm$), followed by the names of any inputs used in the expression,
|
||||
followed by the function's output.
|
||||
|
||||
For example, $\lm x . x + 3$ is the function $f(x) = x + 3$ written in lambda notation.
|
||||
|
||||
\vspace{4mm}
|
||||
Let's disect $\lm x . x + 3$ piece by piece:
|
||||
|
||||
\begin{itemize}[itemsep=3mm]
|
||||
\item \say{$\lm$} tells us that this is the beginning of an expression. \par
|
||||
$\lm$ here doesn't have a special value or definition; \par
|
||||
it's just a symbol that tells us \say{this is the start of a function.}
|
||||
|
||||
|
||||
\item \say{$\lm x$} says that the variable $x$ is \say{bound} to the function (i.e, it is used for input).\par
|
||||
Whenever we see $x$ in the function's output, we'll replace it with the input of the same name.
|
||||
|
||||
\vspace{1mm}
|
||||
|
||||
This is a lot like normal function notation: In $f(x) = x + 3$, $(x)$ is \say{bound}
|
||||
to $f$, and we replace every $x$ we see with our input when evaluating.
|
||||
|
||||
|
||||
|
||||
\item The dot tells us that what follows is the output of this expression. \par
|
||||
This is much like $=$ in our usual function notation: \par
|
||||
The symbols after $=$ in $f(x) = x + 3$ tell us how to compute the output of this function.
|
||||
\end{itemize}
|
||||
|
||||
\problem{}
|
||||
Rewrite the following functions using this notation:
|
||||
\begin{itemize}
|
||||
\item $f(x) = 7x + 4$
|
||||
\item $f(x) = x^2 + 2x + 1$
|
||||
\end{itemize}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
To evaluate $\lm x . x + 3$, we need to input a value:
|
||||
$$
|
||||
(\lm x . x + 3)~5
|
||||
$$
|
||||
This is very similar to the usual way we call functions: we usually write $f(5)$. \par
|
||||
Above, we define our function $f$ \say{in-line} using lambda notation, \par
|
||||
and we omit the parentheses around 5 for the sake of simpler notation.
|
||||
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
|
||||
We evaluate this by removing the \say{$\lm$} prefix and substituting $3$ for $x$ wheverever it appears:
|
||||
$$
|
||||
(\lm x . \tzm{b}x + 3)~\tzmr{a}5 =
|
||||
5 + 3 = 8
|
||||
\begin{tikzpicture}[
|
||||
overlay,
|
||||
remember picture,
|
||||
out=225,
|
||||
in=315,
|
||||
distance=0.5cm
|
||||
]
|
||||
\draw[->,gray,shorten >=5pt,shorten <=3pt]
|
||||
(a.center) to (b.center);
|
||||
\end{tikzpicture}
|
||||
$$
|
||||
|
||||
\problem{}
|
||||
Evaluate the following:
|
||||
\begin{itemize}[itemsep = 2mm]
|
||||
\item $(\lm x. 2x + 1)~4$
|
||||
\item $(\lm x. x^2 + 2x + 1)~3$
|
||||
\item $(\lm x. (\lm y. 9y) x + 3)~2$ \par
|
||||
\hint{
|
||||
This function has a function inside, but the evaluation process doesn't change. \\
|
||||
Replace all $x$ with 2 and evaluate again.
|
||||
}
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\vfill
|
||||
|
||||
As we saw above, we denote function application by simply putting functions next to their inputs. \par
|
||||
If we want to apply $f$ to $5$, we write \say{$f~5$}, without any parentheses around the function's argument.
|
||||
|
||||
\vspace{4mm}
|
||||
|
||||
You may have noticed that we've been using arithmetic in the last few problems.
|
||||
This isn't fully correct: addition is not defined in lambda calculus. In fact, nothing is defined:
|
||||
not even numbers!
|
||||
|
||||
In lambda calculus, we have only one kind of object: the function.
|
||||
The only action we have is function application, which works by just like the examples above.
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
Don't worry if this sounds confusing, we'll see a few examples soon.
|
||||
|
||||
\pagebreak
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\definition{}
|
||||
The first \say{pure} functions we'll define are $I$ and $M$:
|
||||
\begin{itemize}
|
||||
\item $I = \lm x . x$
|
||||
\item $M = \lm x . x x$
|
||||
\end{itemize}
|
||||
Both $I$ and $M$ take one function ($x$) as an input. \par
|
||||
$I$ does nothing, it just returns $x$. \par
|
||||
$M$ is a bit more interesting: it applies the function $x$ on a copy of itself.
|
||||
|
||||
\vspace{4mm}
|
||||
|
||||
Also, note that $I$ and $M$ don't have a meaning on their own. They are not formal functions. \par
|
||||
Rather, they are abbreviations that say \say{write $\lm x.x$ whenever you see $I$.}
|
||||
|
||||
|
||||
|
||||
|
||||
\problem{}
|
||||
Reduce the following expressions. \par
|
||||
\hint{
|
||||
Of course, your final result will be a function. \\
|
||||
Functions are the only objects we have!
|
||||
}
|
||||
|
||||
\begin{itemize}[itemsep=2mm]
|
||||
\item $I~I$
|
||||
\item $M~I$
|
||||
\item $(I~I)~I$
|
||||
\item $\Bigl(~ \lm a .(a~(a~a)) ~\Bigr) ~ I$
|
||||
\item $\Bigl(~(\lm a . (\lm b . a)) ~ M~\Bigr) ~ I$
|
||||
\end{itemize}
|
||||
|
||||
\begin{examplesolution}
|
||||
\textbf{Solution for $(I~I)$:}\par
|
||||
Recall that $I = \lm x.x$. First, we rewrite the left $I$ to get $(\lm x . x )~I$. \par
|
||||
Applying this function by replacing $x$ with $I$, we get $I$:
|
||||
$$
|
||||
I ~ I =
|
||||
(\lm x . \tzm{b}x )~\tzm{a}I =
|
||||
I
|
||||
\begin{tikzpicture}[
|
||||
overlay,
|
||||
remember picture,
|
||||
out=-90,
|
||||
in=-90,
|
||||
distance=0.5cm
|
||||
]
|
||||
\draw[->,gray,shorten >=5pt,shorten <=3pt]
|
||||
(a.center) to (b.east);
|
||||
\end{tikzpicture}
|
||||
$$\null
|
||||
\end{examplesolution}
|
||||
|
||||
|
||||
\vfill
|
||||
|
||||
In lambda calculus, functions are left-associative: \par
|
||||
$(f~g~h)$ means $((f~g)~h)$, not $(f~(g~h))$
|
||||
|
||||
As usual, we use parentheses to group terms if we want to override this order: $(f~(g~h)) \neq ((f~g)~h)$ \par
|
||||
In this handout, all types of parentheses ( $(), [~],$ etc ) are equivalent.
|
||||
|
||||
\problem{}
|
||||
Rewrite the following expressions with as few parentheses as possible, without changing their meaning or structure.
|
||||
Remember that lambda calculus is left-associative.
|
||||
\vspace{2mm}
|
||||
\begin{itemize}[itemsep=2mm]
|
||||
\item $(\lm x. (\lm y. \lm z. ((xz)(yz))))$
|
||||
\item $((ab)(cd))((ef)(gh))$
|
||||
\item $(\lm x. ((\lm y.(yx))(\lm v.v)z)u) (\lm w.w)$
|
||||
\end{itemize}
|
||||
|
||||
\begin{solution}
|
||||
$(\lm x. ((\lm y.(yx))(\lm v.v)z)u) (\lm w.w) \implies (\lm x. (\lm y.yx) (\lm v.v)~z~u) \lm w.w$
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
It's important that a function's output (everything after the dot) will continue until we hit a close-paren.
|
||||
This is why we need the parentheses in the above example.
|
||||
\end{solution}
|
||||
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\definition{Equivalence}
|
||||
We say two functions are \textit{equivalent} if they differ only by the names of their variables:
|
||||
$I = \lm a.a = \lm b.b = \lm \heartsuit . \heartsuit = ...$ \par
|
||||
|
||||
\begin{instructornote}
|
||||
|
||||
The idea behind this is very similar to the idea behind \say{equivalent groups} in group theory: \par
|
||||
we do not care which symbols a certain group or function uses, we care about their \textit{structure}. \par
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
If we have two groups with different elements with the same multiplication table, we look at them as identical groups.
|
||||
The same is true of lambda functions: two lambda functions with different variable names that behave in the same way are identical.
|
||||
|
||||
\end{instructornote}
|
||||
|
||||
|
||||
|
||||
\definition{}
|
||||
Let $K = \lm a. (\lm b . a)$. We'll call $K$ the \say{constant function function.}
|
||||
|
||||
\problem{}
|
||||
That's not a typo. Why does this name make sense? \par
|
||||
\hint{What is $K~x$?}
|
||||
|
||||
\begin{solution}
|
||||
$K x = \lm a . x$, which is a constant function that always outputs $x$. \par
|
||||
Given an argument, $K$ returns a constant function with that value.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Show that associativity matters by evaluating $\bigl((M~K)~I\bigr)$ and $\bigl(M~(K~I)\bigr)$. \par
|
||||
What would $M~K~I$ reduce to?
|
||||
|
||||
\begin{solution}
|
||||
$\bigl((M~K)~I\bigr) = (K~K)~I = (\lm a.K)~I = K$ \par
|
||||
$\bigl(M~(K~I)\bigr) = M~(\lm a.I) = (\lm a.I)(\lm a.I) = I$
|
||||
\end{solution}
|
||||
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\generic{Currying:}
|
||||
|
||||
In lambda calculus, functions are only allowed to take one argument. \par
|
||||
If we want multivariable functions, we'll have to emulate them through \textit{currying}\footnotemark{}\hspace{-1ex}.
|
||||
|
||||
\footnotetext{After Haskell Brooks Curry\footnotemark{}\hspace{-1ex}, a logician that contributed to the theory of functional computation.}
|
||||
\footnotetext{
|
||||
There are three programming languages named after him: Haskell, Brook, and Curry. \par
|
||||
Two of these are functional, and one is an oddball GPU language last released in 2007.
|
||||
}
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
The idea behind currying is fairly simple: we make functions that return functions. \par
|
||||
We've already seen this on the previous page: $K$ takes an input $x$ and uses it to construct a constant function.
|
||||
You can think of $K$ as a \say{factory} that constructs functions using the input we provide.
|
||||
|
||||
\problem{}<firstcardinal>
|
||||
\vspace{1mm} % Slight gap for big paren
|
||||
Let $C = \lm f. \Bigl[\lm g. \Bigl( \lm x. [~ f(g(x)) ~] \Bigr)\Bigr]$. For now, we'll call it the \say{composer.} \par
|
||||
\note[Note]{We could also call $C$ the \say{right-associator.} Why?}
|
||||
|
||||
\vspace{3mm}
|
||||
|
||||
$C$ has three \say{layers} of curry: it makes a function ($\lm g$) that makes another function ($\lm x$). \par
|
||||
If we look closely, we'll find that $C$ pretends to take three arguments.
|
||||
|
||||
\vspace{1mm}
|
||||
|
||||
What does $C$ do? Evaluate $(C~a~b~x)$ for arbitrary expressions $a, b,$ and $x$. \par
|
||||
\hint{Evaluate $(C~a)$ first. Remember, function application is left-associative.}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Using the definition of $C$ above, evaluate $C~M~I~\star$ \par
|
||||
Then, evaluate $C~I~M~I$ \par
|
||||
\note[Note]{$\star$ represents an arbitrary expression. Treat it like an unknown variable.}
|
||||
|
||||
\vfill
|
||||
|
||||
As we saw above, currying allows us to create multivariable functions by nesting single-variable functions.
|
||||
You may have notice that curried expressions can get very long. We'll use a bit of shorthand to make them more palatable:
|
||||
If we have an expression with repeated function definitions, we'll combine their arguments under one $\lm$.
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
For example, $A = \lm f .[ \lm a . f(f(a))]$ will become $A = \lm fa . f(f(a))$
|
||||
|
||||
\problem{}
|
||||
Rewrite $C = \lm f.\lm g.\lm x. (g(f(x)))$ from \ref{firstcardinal} using this shorthand.
|
||||
|
||||
\vspace{25mm}
|
||||
|
||||
Remember that this is only notation. \textbf{Curried functions are not multivariable functions, they are simply shorthand!}
|
||||
Any function presented with this notation must still be evaluated one variable at a time, just like an un-curried function.
|
||||
Substituting all curried variables at once will cause errors.
|
||||
|
||||
\pagebreak
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%\iftrue
|
||||
\iffalse
|
||||
\generic{$\alpha$-Conversion:}
|
||||
There is one more operation we need to discuss. Those of you that have worked with any programming language may
|
||||
find that this section sounds like something you've seen before.
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
Variables inside functions are \say{scoped.} We must take care to keep separate variables separate.
|
||||
|
||||
For example, take the functions \par
|
||||
$A = \lm a b . a$ \par
|
||||
$B = \lm b . b$
|
||||
|
||||
\vspace{2ex}
|
||||
|
||||
We could say that $(A~B) = \lm b . (\lm b . b)$, and therefore
|
||||
$$
|
||||
((A~B)~I)
|
||||
= (~ (\lm \tzm{b}b . (\lm b . b))~\tzmr{a}I ~)
|
||||
= \lm I . I
|
||||
\begin{tikzpicture}[
|
||||
overlay,
|
||||
remember picture,
|
||||
out=225,
|
||||
in=315,
|
||||
distance=0.5cm
|
||||
]
|
||||
\draw[->,gray,shorten >=5pt,shorten <=3pt]
|
||||
(a.center) to (b.center);
|
||||
\end{tikzpicture}
|
||||
$$
|
||||
|
||||
Which is, of course, incorrect. $\lm I . I$ is not a valid function.
|
||||
This problem arises because both $A$ and $B$ use the input $b$.
|
||||
However, each $b$ is \say{bound} to a different function:
|
||||
One $b$ is bound to $A$, and the other to $B$. They are therefore distinct.
|
||||
|
||||
\vspace{2ex}
|
||||
|
||||
Let's rewrite $B$ as $\lm b_1 . b_1$ and try again: $(A~B) = \lm b . ( \lm b_1 . b_1) = \lm bb_1 . b_1$ \par
|
||||
Now, we correctly find that $(A~B~I) = (\lm bc . c)~I = \lm c . c = B = I$.
|
||||
\fi
|
||||
|
||||
\problem{}
|
||||
Let $Q = \lm abc.b$. Reduce $(Q~a~c~b)$. \par
|
||||
\hint{
|
||||
You may want to rename a few variables. \\
|
||||
The $a,b,c$ in $Q$ are different than the $a,b,c$ in the expression!
|
||||
}
|
||||
|
||||
\begin{solution}
|
||||
I'll rewrite $(Q~a~c~b)$ as $(Q~a_1~c_1~b_1)$:
|
||||
\begin{align*}
|
||||
Q = (\lm abc.b) &= (\lm a.\lm b.\lm c.b) \\
|
||||
(\lm a.\lm b.\lm c.b)~a_1 &= (\lm b.\lm c.b) \\
|
||||
(\lm b.\lm c.b)~c_1 &= (\lm c.c_1) \\
|
||||
(\lm c.c_1)~b_1 &= c_1
|
||||
\end{align*}
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Reduce $((\lm a.a)~\lm bc.b)~d~\lm eg.g$
|
||||
|
||||
\begin{solution}
|
||||
$((\lm a.a)~\lm bc.b)~d~\lm eg.g$ \\
|
||||
$= (\lm bc.b)~d~\lm eg.g$ \\
|
||||
$= (\lm c.d)~\lm eg.g$ \\
|
||||
$= d$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
42
src/Advanced/Lambda Calculus/parts/01 combinators.tex
Executable file
42
src/Advanced/Lambda Calculus/parts/01 combinators.tex
Executable file
@ -0,0 +1,42 @@
|
||||
\section{Combinators}
|
||||
|
||||
\definition{}
|
||||
A \textit{free variable} in a $\lm$-expression is a variable that isn't bound to any input. \par
|
||||
For example, $b$ is a free variable in $(\lm a.a)~b$.
|
||||
|
||||
\definition{Combinators}
|
||||
A \textit{combinator} is a lambda expression with no free variables.
|
||||
|
||||
\vspace{1mm}
|
||||
|
||||
Notable combinators are often named after birds.\hspace{-0.5ex}\footnotemark{} We've already met a few: \par
|
||||
The \textit{Idiot}, $I = \lm a.a$ \par
|
||||
The \textit{Mockingbird}, $M = \lm f.ff$ \par
|
||||
The \textit{Cardinal}, $C = \lm fgx.(~ f(g(x)) ~)$
|
||||
The \textit{Kestrel}, $K = \lm ab . a$
|
||||
|
||||
|
||||
|
||||
\problem{}
|
||||
If we give the Kestrel two arguments, it does something interesting: \par
|
||||
It selects the first and rejects the second. \par
|
||||
Convince yourself of this fact by evaluating $(K~\heartsuit~\star)$.
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}<kitedef>
|
||||
Modify the Kestrel so that it selects its \textbf{second} argument and rejects the first. \par
|
||||
|
||||
\begin{solution}
|
||||
$\lm ab . b$.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
We'll call the combinator from \ref{kitedef} the \textit{Kite}, $KI$. \par
|
||||
Show that we can also obtain the kite by evaluating $(K~I)$.
|
||||
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
77
src/Advanced/Lambda Calculus/parts/02 boolean.tex
Executable file
77
src/Advanced/Lambda Calculus/parts/02 boolean.tex
Executable file
@ -0,0 +1,77 @@
|
||||
\section{Boolean Algebra}
|
||||
|
||||
The Kestrel selects its first argument, and the Kite selects its second. \par
|
||||
Maybe we can somehow put this \say{choosing} behavior to work...
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
Let $T = K\phantom{I} = \lm ab . a$ \par
|
||||
Let $F = KI = \lm ab . b$
|
||||
|
||||
\problem{}
|
||||
Write a function $\text{NOT}$ so that $(\text{NOT} ~ T) = F$ and $(\text{NOT}~F) = T$. \par
|
||||
\hint{What is $(T~\heartsuit~\star)$? How about $(F~\heartsuit~\star)$?}
|
||||
|
||||
|
||||
\begin{solution}
|
||||
$\text{NOT} = \lm a . (a~F~T)$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
How would \say{if} statements work in this model of boolean logic? \par
|
||||
Say we have a boolean $B$ and two expressions $E_T$ and $E_F$.
|
||||
Can we write a function that evaluates to $E_T$ if $B$ is true, and to $E_F$ otherwise?
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
\problem{}
|
||||
Write functions $\text{AND}$, $\text{OR}$, and $\text{XOR}$ that satisfy the following table.
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{|| c c || c | c | c ||}
|
||||
\hline
|
||||
$A$ & $B$ & $(\text{AND}~A~B)$ & $(\text{OR}~A~B)$ & $(\text{XOR}~A~B)$ \\
|
||||
\hline\hline
|
||||
F & F & F & F & F \\
|
||||
\hline
|
||||
F & T & F & T & T \\
|
||||
\hline
|
||||
T & F & F & T & T \\
|
||||
\hline
|
||||
T & T & T & T & F \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\begin{solution}
|
||||
There's more than one way to do this, of course.
|
||||
\begin{align*}
|
||||
\text{AND} &= \lm ab . (a~b~F) = \lm ab . aba \\
|
||||
\text{OR} &= \lm ab . (a~T~b) = \lm ab . aab \\
|
||||
\text{XOR} &= \lm ab . (a~ (\text{NOT}~b) ~b)
|
||||
\end{align*}
|
||||
|
||||
Another clever solution is $\text{OR} = \lm ab.(M~a~b)$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
To complete our boolean algebra, construct the boolean equality check EQ. \par
|
||||
What inputs should it take? What outputs should it produce?
|
||||
|
||||
\begin{solution}
|
||||
$\text{EQ} = \lm ab . [a~(bTF)~(bFT)] = \lm ab . [a~b~(\text{NOT}~b)]$
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
$\text{EQ} = \lm ab . [\text{NOT}~(\text{XOR}~a~b)]$
|
||||
\end{solution}
|
||||
|
||||
|
||||
\vfill
|
||||
|
||||
\pagebreak
|
175
src/Advanced/Lambda Calculus/parts/03 numbers.tex
Executable file
175
src/Advanced/Lambda Calculus/parts/03 numbers.tex
Executable file
@ -0,0 +1,175 @@
|
||||
\section{Numbers}
|
||||
|
||||
Since the only objects we have in $\lm$ calculus are functions, it's natural to think of quantities as \textit{adverbs} (once, twice, thrice,...) rather than \textit{nouns} (one, two, three ...)
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
We'll start with zero. If our numbers are \textit{once,} \textit{twice,} and \textit{twice}, it may make sense to make zero \textit{don't}. \par
|
||||
Here's our \textit{don't} function: given a function and an input, don't apply the function to the input.
|
||||
$$
|
||||
0 = \lm fa.a
|
||||
$$
|
||||
If you look closely, you'll find that $0$ is equivalent to the false function $F$.
|
||||
|
||||
\problem{}
|
||||
Write $1$, $2$, and $3$. We will call these \textit{Church numerals}.\hspace{-0.5ex}\footnotemark{} \\
|
||||
\note{\textit{Note:} This problem read aloud is \say{Define \textit{once}, \textit{twice}, and \textit{thrice}.}}
|
||||
|
||||
\footnotetext{after Alonzo Church, the inventor of lambda calculus and these numerals. He was Alan Turing's thesis advisor.}
|
||||
|
||||
\begin{solution}
|
||||
$1$ calls a function once on its argument: \par
|
||||
$1 = \lm fa . (f~a)$.
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
Naturally, \par
|
||||
$2 = \lm fa . [~f~(f~a)~]$ \par
|
||||
$3 = \lm fa . [~f~(f~(f~a))~]$
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
The round parentheses are \textit{essential}. Our lambda calculus is left-associative! \par
|
||||
Also, note that zero is false and one is the (two-variable) identity.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
What is $(4~I)~\star$?
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
What is $(3~NOT~T)$? \par
|
||||
How about $(8~NOT~F)$?
|
||||
|
||||
\vfill
|
||||
|
||||
\pagebreak
|
||||
|
||||
\problem{}
|
||||
Peano's axioms state that we only need a zero element and a \say{successor} operation to
|
||||
build the natural numbers. We've already defined zero.
|
||||
Now, create a successor operation so that $1 \coloneqq S(0)$, $2 \coloneqq S(1)$, and so on. \par
|
||||
\hint{A good signature for this function is $\lm nfa$, or more clearly $\lm n.\lm fa$. Do you see why?}
|
||||
|
||||
\begin{solution}
|
||||
$S = \lm n. [\lm fa . f~(n~f~a)] = \lm nfa . [f~(n~f~a)]$
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
Do $f$ $n$ times, then do $f$ one more time.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Verify that $S(0) = 1$ and $S(1) = 2$.
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
|
||||
Assume that only Church numerals will be passed to the functions in the following problems. \par
|
||||
We make no promises about their output if they're given anything else.
|
||||
|
||||
\problem{}
|
||||
Define a function ADD that adds two Church numerals.
|
||||
|
||||
\begin{solution}
|
||||
$\text{ADD} = \lm mn . (m~S~n) = \lm mn . (n~S~m)$
|
||||
\end{solution}
|
||||
|
||||
\begin{instructornote}
|
||||
Defining \say{equivalence} is a bit tricky. The solution above illustrates the problem pretty well.
|
||||
|
||||
\note{Note: The notions of \say{extensional} and \say{intentional} equivalence may be interesting in this context. Do some reading on your own.
|
||||
}
|
||||
|
||||
\vspace{4ex}
|
||||
|
||||
These two definitions of ADD are equivalent if we apply them to Church numerals. If we were to apply these two versions of ADD to functions that behave in a different way, we'll most likely get two different results! \\
|
||||
As a simple example, try applying both versions of ADD to the Kestrel and the Kite.
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
To compare functions that aren't $\alpha$-equivalent, we'll need to restrict our domain to functions of a certain form, saying that two functions are equivalent over a certain domain. \\
|
||||
\end{instructornote}
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Design a function MULT that multiplies two numbers. \par
|
||||
\hint{The easy solution uses ADD, the elegant one doesn't. Find both!}
|
||||
|
||||
\begin{solution}
|
||||
$\text{MULT} = \lm mn . [m~(\text{ADD}~n)~m]$
|
||||
|
||||
$\text{MULT} = \lm mnf . [m~(n~f)]$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
|
||||
\problem{}
|
||||
Define the functions $Z$ and $NZ$. $Z$ should reduce to $T$ if its input was zero, and $F$ if it wasn't. \par
|
||||
$NZ$ does the opposite. $Z$ and $NZ$ should look fairly similar.
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
\begin{solution}
|
||||
$Z\phantom{N} = \lm n .[n~(\lm a.F)~T]$ \par
|
||||
$NZ = \lm n .[n~(\lm a.T)~F]$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Design an expression PAIR that constructs two-value tuples. \par
|
||||
For example, say $A = \text{PAIR}~1~2$. Then, \par
|
||||
$(A~T)$ should reduce to $1$ and $(A~F)$ should reduce to $2$.
|
||||
|
||||
\begin{solution}
|
||||
$\text{PAIR} = \lm ab . \lm i . (i~a~b) = \lm abi.iab$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
From now on, I'll write (PAIR $A$ $B$) as $\langle A,B \rangle$. \par
|
||||
Like currying, this is only notation. The underlying logic remains the same.
|
||||
|
||||
\pagebreak
|
||||
|
||||
\problem{}<shiftadd>
|
||||
Write a function $H$, which we'll call \say{shift and add.} \par
|
||||
It does exactly what it says on the tin:
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
Given an input pair, it should shift its second argument left, then add one. \par
|
||||
$H~\langle 0, 1 \rangle$ should reduce to $\langle 1, 2\rangle$ \par
|
||||
$H~\langle 1, 2 \rangle$ should reduce to $\langle 2, 3\rangle$ \par
|
||||
$H~\langle 10, 4 \rangle$ should reduce to $\langle 4, 5\rangle$
|
||||
|
||||
\begin{solution}
|
||||
$H = \lm p . \Bigl\langle~(p~F)~,~S(p~F)~\Bigr\rangle$
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
Note that $H~\langle 0, 0 \rangle$ reduces to $\langle 0, 1 \rangle$
|
||||
\end{solution}
|
||||
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}<decrement>
|
||||
Design a function $D$ that un-does $S$. That means \par
|
||||
$D(1) = 0$, $D(2) = 1$, etc. $D(0)$ should be zero. \par
|
||||
\hint{$H$ will help you make an elegant solution.}
|
||||
|
||||
\begin{solution}
|
||||
$D = \lm n . \Bigl[(~n~H~\langle 0, 0 \rangle~)~T\Bigr]$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
162
src/Advanced/Lambda Calculus/parts/04 recursion.tex
Executable file
162
src/Advanced/Lambda Calculus/parts/04 recursion.tex
Executable file
@ -0,0 +1,162 @@
|
||||
\section{Recursion}
|
||||
|
||||
|
||||
%\iftrue
|
||||
\iffalse
|
||||
|
||||
You now have a choice. Choose wisely --- there's no going back.
|
||||
|
||||
\begin{tcolorbox}[
|
||||
breakable,
|
||||
colback=white,
|
||||
colframe=gray,
|
||||
arc=0pt, outer arc=0pt
|
||||
]
|
||||
\raggedright
|
||||
\textbf{Take the red pill:} You stay on this page and try to solve \ref{thechallenge}. \par
|
||||
This will take a while, and it's very unlikely you'll finish before class ends.
|
||||
|
||||
|
||||
\vspace{4mm}
|
||||
|
||||
I strongly prefer this option. It's not easy, but you'll be very happy if you solve it yourself.
|
||||
This is a chance to build your own solution to a fundamental problem in this field, just as
|
||||
Curry, Church, and Turing did when first developing the theory of lambda calculus.
|
||||
|
||||
- Mark
|
||||
\end{tcolorbox}
|
||||
|
||||
\begin{tcolorbox}[
|
||||
breakable,
|
||||
colback=white,
|
||||
colframe=gray,
|
||||
arc=0pt, outer arc=0pt
|
||||
]
|
||||
\textbf{Take the blue pill:} You skip this problem and turn the page.
|
||||
Half of the answer to \ref{thechallenge} will be free, and the rest will be
|
||||
broken into smaller steps. This is how we usually learn out about interesting
|
||||
mathematics, both in high school and in university.
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
This path isn't as rewarding as the one above, but it is well-paved
|
||||
and easier to traverse.
|
||||
\end{tcolorbox}
|
||||
|
||||
\problem{}<thechallenge>
|
||||
Can you find a way to recursively call functions in lambda calculus? \par
|
||||
Find a way to define a recursive factorial function. \par
|
||||
|
||||
\note{$A = (\lm a. A~a)$ doesn't count. You can't use a macro inside itself.}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
\fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Say we want a function that computes the factorial of a positive integer. Here's one way we could define it:
|
||||
$$
|
||||
x! = \begin{cases}
|
||||
x \times (x-1)! & x \neq 0 \\
|
||||
1 & x = 0
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
We cannot re-create this in lambda calculus, since we aren't given a way to recursively call functions.
|
||||
|
||||
\vspace{2mm}
|
||||
|
||||
One could think that $A = \lm a. A~a$ is a recursive function. In fact, it is not. \par
|
||||
Remember that such \say{definitions} aren't formal structures in lambda calculus. \par
|
||||
They're just shorthand that simplifies notation.
|
||||
|
||||
\begin{instructornote}
|
||||
We're talking about recursion, and \textit{computability} isn't far away. At one point or another, it may be good to give the class a precise definition of \say{computable by lambda calculus:}
|
||||
|
||||
\vspace{4ex}
|
||||
|
||||
Say we have a device that reduces a $\lm$ expression to $\beta$-normal form. We give it an expression, and the machine simplifies it as much as it can and spits out the result.
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
An algorithm is \say{computable by lambda calculus} if we can encode its input in an expression that resolves to the algorithm's output.
|
||||
\end{instructornote}
|
||||
|
||||
\problem{}
|
||||
Write an expression that resolves to itself. \par
|
||||
\hint{Your answer should be quite short.}
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
This expression is often called $\Omega$, after the last letter of the Greek alphabet. \par
|
||||
$\Omega$ useless on its own, but it gives us a starting point for recursion. \par
|
||||
|
||||
\begin{solution}
|
||||
$\Omega = M~M = (\lm x . xx) (\lm x . xx)$
|
||||
|
||||
\vspace{1mm}
|
||||
|
||||
An uninspired mathematician might call the Mockingbird $\omega$, \say{little omega}.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\definition{}
|
||||
This is the \textit{Y-combinator}. You may notice that it's just $\Omega$ put to work.
|
||||
$$
|
||||
Y = \lm f . (\lm x . f(x~x))(\lm x . f(x~x))
|
||||
$$
|
||||
|
||||
\problem{}
|
||||
What does this thing do? \par
|
||||
Evaluate $Y f$.
|
||||
|
||||
|
||||
|
||||
%\vfill
|
||||
|
||||
%\definition{}
|
||||
%We say $x$ is a \textit{fixed point} of a function $f$ if $f(x) = x$.
|
||||
|
||||
%\problem{}
|
||||
%Show that $Y F$ is a fixed point of $F$.
|
||||
|
||||
%\vfill
|
||||
|
||||
%\problem{}
|
||||
%Let $b = (\lm xy . y(xxy))$ and $B = b ~ b$. \par
|
||||
%Let $N = B F$ for an arbitrary lambda expression $F$. \par
|
||||
|
||||
%Show that $F N = N$.
|
||||
|
||||
%\vfill
|
||||
|
||||
%\problem{Bonus}
|
||||
%Find a fixed-point combinator that isn't $Y$ or $\Theta$.
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
130
src/Advanced/Lambda Calculus/parts/05 challenges.tex
Executable file
130
src/Advanced/Lambda Calculus/parts/05 challenges.tex
Executable file
@ -0,0 +1,130 @@
|
||||
\section{Challenges}
|
||||
|
||||
Do \ref{Yfac} first, then finish the rest in any order.
|
||||
|
||||
\problem{}<Yfac>
|
||||
Design a recursive factorial function using $Y$.
|
||||
|
||||
\begin{solution}
|
||||
$\text{FAC} = \lm yn.[Z~n][1][\text{MULT}~n~(y~(\text{D}~n))]$
|
||||
|
||||
To compute the factorial of 5, evaluate $(\text{Y}~\text{FAC}~5)$.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Design a non-recursive factorial function. \par
|
||||
\note{This one is easier than \ref{Yfac}, but I don't think it will help you solve it.}
|
||||
|
||||
\begin{solution}
|
||||
$\text{FAC}_0 = \lm p .
|
||||
\Bigl\langle~~
|
||||
\Bigl[D~(p~t)\Bigr]
|
||||
~,~
|
||||
\Bigl[\text{MULT}~(p~T)~(p~F)\Bigr]
|
||||
~~\Bigr\rangle
|
||||
$
|
||||
|
||||
\vspace{2ex}
|
||||
|
||||
$
|
||||
\text{FAC} = \lm n .
|
||||
\bigl( n~\text{FAC}_0~\langle n, 1 \rangle \bigr)
|
||||
$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
|
||||
|
||||
\problem{}
|
||||
Solve \ref{decrement} without using $H$. \par
|
||||
In \ref{decrement}, we created the \say{decrement} function.
|
||||
|
||||
\begin{solution}
|
||||
One solution is below. Can you figure out how it works? \par
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
$
|
||||
D_0 =
|
||||
\lm p . \Bigl[p~T\Bigr]
|
||||
\Bigl\langle
|
||||
F ~,~ p~F
|
||||
\Bigr\rangle
|
||||
\Bigl\langle
|
||||
F
|
||||
~,~
|
||||
\bigl\langle
|
||||
p~F~T ~,~ ( (p~F~T)~(P~F~F) )
|
||||
\bigr\rangle
|
||||
\Bigr\rangle
|
||||
$
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
$
|
||||
D = \lm nfa .
|
||||
\Bigl(
|
||||
n D_0 \Bigl\langle T, \langle f, a \rangle \Bigr\rangle
|
||||
\Bigr)~F~F
|
||||
$
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
|
||||
|
||||
|
||||
\problem{}
|
||||
Using pairs, make a \say{list} data structure. Define a GET function, so that $\text{GET}~L~n$ reduces to the nth item in the list.
|
||||
$\text{GET}~L~0$ should give the first item in the list, and $\text{GET}~L~1$, the \textit{second}. \par
|
||||
Lists have a defined length, so you should be able to tell when you're on the last element.
|
||||
|
||||
\begin{solution}
|
||||
One possible implementation is
|
||||
$\Bigl\langle
|
||||
\langle \text{is last} ~,~ \text{item} \rangle
|
||||
~,~
|
||||
\text{next}...
|
||||
\Bigr\rangle$, where:
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
\say{is last} is a boolean, true iff this is the last item in the list. \par
|
||||
\say{item} is the thing you're storing \par
|
||||
\say{next...} is another one of these list fragments.
|
||||
|
||||
It doesn't matter what \say{next} is in the last list fragment. A dedicated \say{is last} slot allows us to store arbitrary functions in this list.
|
||||
|
||||
\vspace{1ex}
|
||||
|
||||
Here, $\text{GET} = \lm nL.[(n~L~F)~T~F$]
|
||||
|
||||
This will break if $n$ is out of range.
|
||||
\end{solution}
|
||||
|
||||
\vfill
|
||||
\pagebreak
|
||||
|
||||
\problem{}
|
||||
Write a lambda expression that represents the Fibonacci function: \par
|
||||
$f(0) = 1$, $f(1) = 1$, $f(n + 2) = f(n + 1) + f(n)$.
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Write a lambda expression that evaluates to $T$ if a number $n$ is prime, and to $F$ otherwise.
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{}
|
||||
Write a function MOD so that $(\text{MOD}~a~b)$ reduces to the remainder of $a \div b$.
|
||||
|
||||
\vfill
|
||||
|
||||
\problem{Bonus}
|
||||
Play with \textit{Lamb}, an automatic lambda expression evaluator. \par
|
||||
\url{https://git.betalupi.com/Mark/lamb}
|
||||
|
||||
\pagebreak
|
Reference in New Issue
Block a user