Finished implementing Maps

This commit is contained in:
Wen Kokke 2017-06-21 16:59:10 +02:00
parent 044f4d0263
commit 1c9b86fb26
No known key found for this signature in database
GPG key ID: EF467CD387487CB8
5 changed files with 246 additions and 785 deletions

20
Gemfile
View file

@ -1,28 +1,10 @@
source "https://rubygems.org"
ruby RUBY_VERSION
# Hello! This is where you manage which Jekyll version is used to run.
# When you want to use a different version, change it below, save the
# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
#
# bundle exec jekyll serve
#
# This will help ensure the proper Jekyll version is running.
# Happy Jekylling!
gem "jekyll", "3.4.2"
# This is the default theme for new Jekyll sites. You may change this to anything you like.
gem "minima", "~> 2.0"
gem "github-pages", group: :jekyll_plugins
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
# gem "github-pages", group: :jekyll_plugins
# If you have any plugins, put them here!
group :jekyll_plugins do
gem "jekyll-feed", "~> 0.6"
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

View file

@ -1,12 +1,79 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.5.0)
activesupport (4.2.8)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
colorator (1.1.0)
ethon (0.10.1)
ffi (>= 1.3.0)
execjs (2.7.0)
faraday (0.12.1)
multipart-post (>= 1.2, < 3)
ffi (1.9.18)
forwardable-extended (2.6.0)
jekyll (3.4.2)
gemoji (3.0.0)
github-pages (140)
activesupport (= 4.2.8)
github-pages-health-check (= 1.3.4)
jekyll (= 3.4.3)
jekyll-avatar (= 0.4.2)
jekyll-coffeescript (= 1.0.1)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.9.2)
jekyll-gist (= 1.4.0)
jekyll-github-metadata (= 2.3.1)
jekyll-mentions (= 1.2.0)
jekyll-optional-front-matter (= 0.1.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.1.0)
jekyll-redirect-from (= 0.12.1)
jekyll-relative-links (= 0.4.0)
jekyll-sass-converter (= 1.5.0)
jekyll-seo-tag (= 2.2.3)
jekyll-sitemap (= 1.0.0)
jekyll-swiss (= 0.4.0)
jekyll-theme-architect (= 0.0.4)
jekyll-theme-cayman (= 0.0.4)
jekyll-theme-dinky (= 0.0.4)
jekyll-theme-hacker (= 0.0.4)
jekyll-theme-leap-day (= 0.0.4)
jekyll-theme-merlot (= 0.0.4)
jekyll-theme-midnight (= 0.0.4)
jekyll-theme-minimal (= 0.0.4)
jekyll-theme-modernist (= 0.0.4)
jekyll-theme-primer (= 0.2.1)
jekyll-theme-slate (= 0.0.4)
jekyll-theme-tactile (= 0.0.4)
jekyll-theme-time-machine (= 0.0.4)
jekyll-titles-from-headings (= 0.1.5)
jemoji (= 0.8.0)
kramdown (= 1.13.2)
liquid (= 3.0.6)
listen (= 3.0.6)
mercenary (~> 0.3)
minima (= 2.1.1)
rouge (= 1.11.1)
terminal-table (~> 1.4)
github-pages-health-check (1.3.4)
addressable (~> 2.3)
net-dns (~> 0.8)
octokit (~> 4.0)
public_suffix (~> 2.0)
typhoeus (~> 0.7)
html-pipeline (2.6.0)
activesupport (>= 2)
nokogiri (>= 1.4)
i18n (0.8.4)
jekyll (3.4.3)
addressable (~> 2.4)
colorator (~> 1.0)
jekyll-sass-converter (~> 1.0)
@ -17,41 +84,119 @@ GEM
pathutil (~> 0.9)
rouge (~> 1.7)
safe_yaml (~> 1.0)
jekyll-feed (0.9.1)
jekyll-avatar (0.4.2)
jekyll (~> 3.0)
jekyll-coffeescript (1.0.1)
coffee-script (~> 2.2)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
jekyll-feed (0.9.2)
jekyll (~> 3.3)
jekyll-gist (1.4.0)
octokit (~> 4.2)
jekyll-github-metadata (2.3.1)
jekyll (~> 3.1)
octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.2.0)
activesupport (~> 4.0)
html-pipeline (~> 2.3)
jekyll (~> 3.0)
jekyll-optional-front-matter (0.1.2)
jekyll (~> 3.0)
jekyll-paginate (1.1.0)
jekyll-readme-index (0.1.0)
jekyll (~> 3.0)
jekyll-redirect-from (0.12.1)
jekyll (~> 3.3)
jekyll-relative-links (0.4.0)
jekyll (~> 3.3)
jekyll-sass-converter (1.5.0)
sass (~> 3.4)
jekyll-seo-tag (2.2.3)
jekyll (~> 3.3)
jekyll-sitemap (1.0.0)
jekyll (~> 3.3)
jekyll-swiss (0.4.0)
jekyll-theme-architect (0.0.4)
jekyll (~> 3.3)
jekyll-theme-cayman (0.0.4)
jekyll (~> 3.3)
jekyll-theme-dinky (0.0.4)
jekyll (~> 3.3)
jekyll-theme-hacker (0.0.4)
jekyll (~> 3.3)
jekyll-theme-leap-day (0.0.4)
jekyll (~> 3.3)
jekyll-theme-merlot (0.0.4)
jekyll (~> 3.3)
jekyll-theme-midnight (0.0.4)
jekyll (~> 3.3)
jekyll-theme-minimal (0.0.4)
jekyll (~> 3.3)
jekyll-theme-modernist (0.0.4)
jekyll (~> 3.3)
jekyll-theme-primer (0.2.1)
jekyll (~> 3.3)
jekyll-theme-slate (0.0.4)
jekyll (~> 3.3)
jekyll-theme-tactile (0.0.4)
jekyll (~> 3.3)
jekyll-theme-time-machine (0.0.4)
jekyll (~> 3.3)
jekyll-titles-from-headings (0.1.5)
jekyll (~> 3.3)
jekyll-watch (1.5.0)
listen (~> 3.0, < 3.1)
jemoji (0.8.0)
activesupport (~> 4.0)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0)
kramdown (1.13.2)
liquid (3.0.6)
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
listen (3.0.6)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9.7)
mercenary (0.3.6)
minima (2.1.0)
mini_portile2 (2.2.0)
minima (2.1.1)
jekyll (~> 3.3)
minitest (5.10.2)
multipart-post (2.0.0)
net-dns (0.8.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
octokit (4.7.0)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.14.0)
forwardable-extended (~> 2.6)
public_suffix (2.0.5)
rb-fsevent (0.9.8)
rb-inotify (0.9.8)
ffi (>= 0.5.0)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
rouge (1.11.1)
safe_yaml (1.0.4)
sass (3.4.23)
sass (3.4.24)
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
typhoeus (0.8.0)
ethon (>= 0.8.0)
tzinfo (1.2.3)
thread_safe (~> 0.1)
unicode-display_width (1.3.0)
PLATFORMS
ruby
DEPENDENCIES
jekyll (= 3.4.2)
github-pages
jekyll-feed (~> 0.6)
minima (~> 2.0)
tzinfo-data
RUBY VERSION
ruby 2.4.0p0
BUNDLED WITH
1.14.6
1.15.0

View file

@ -4,7 +4,8 @@ layout : page
permalink : /Basics
---
<pre class="Agda">{% raw %}
<pre class="Agda">
<a name="113" class="Keyword"
>open</a
><a name="117"
@ -34,7 +35,8 @@ permalink : /Basics
><a name="179" class="Symbol"
>)</a
>
{% endraw %}</pre>
</pre>
The functional programming style brings programming closer to
simple, everyday mathematics: If a procedure or method has no side
@ -87,7 +89,8 @@ very simple example.
The following declaration tells Agda that we are defining
a new set of data values -- a *type*.
<pre class="Agda">{% raw %}
<pre class="Agda">
<a name="2469" class="Keyword"
>data</a
><a name="2473"
@ -198,7 +201,8 @@ a new set of data values -- a *type*.
><a name="2612" href="Basics.html#2474" class="Datatype"
>Day</a
>
{% endraw %}</pre>
</pre>
The type is called `day`, and its members are `monday`,
`tuesday`, etc. The second and following lines of the definition
@ -207,7 +211,8 @@ can be read "`monday` is a `day`, `tuesday` is a `day`, etc."
Having defined `day`, we can write functions that operate on
days.
<pre class="Agda">{% raw %}
<pre class="Agda">
<a name="2894" href="Basics.html#2894" class="Function"
>nextWeekday</a
><a name="2905"
@ -346,7 +351,8 @@ days.
><a name="3135" href="Basics.html#2492" class="InductiveConstructor"
>monday</a
>
{% endraw %}</pre>
</pre>
One thing to note is that the argument and return types of
this function are explicitly declared. Like most functional
@ -369,7 +375,8 @@ above example to Agda, and observe the result.
Second, we can record what we *expect* the result to be in the
form of an Agda type:
<pre class="Agda">{% raw %}
<pre class="Agda">
<a name="4097" href="Basics.html#4097" class="Function Operator"
>test_nextWeekday</a
><a name="4113"
@ -401,7 +408,8 @@ form of an Agda type:
><a name="4153" href="Basics.html#2510" class="InductiveConstructor"
>tuesday</a
>
{% endraw %}</pre>
</pre>
This declaration does two things: it makes an assertion (that the second
weekday after `saturday` is `tuesday`), and it gives the assertion a name
@ -410,7 +418,8 @@ that can be used to refer to it later.
Having made the assertion, we must also verify it. We do this by giving
a term of the above type:
<pre class="Agda">{% raw %}
<pre class="Agda">
<a name="4472" href="Basics.html#4097" class="Function Operator"
>test_nextWeekday</a
><a name="4488"
@ -422,7 +431,8 @@ a term of the above type:
><a name="4491" href="https://agda.github.io/agda-stdlib/Agda.Builtin.Equality.html#140" class="InductiveConstructor"
>refl</a
>
{% endraw %}</pre>
</pre>
There is no essential difference between the definition for
`test_nextWeekday` here and the definition for `nextWeekday` above,

View file

@ -11,7 +11,7 @@ a nice case study using ideas we've seen in previous chapters, including
building data structures out of higher-order functions (from [Basics]({{
"Basics" | relative_url }}) and [Poly]({{ "Poly" | relative_url }}) and the use
of reflection to streamline proofs (from [IndProp]({{ "IndProp" | relative_url
}})).
}})).
We'll define two flavors of maps: _total_ maps, which include a
"default" element to be returned when a key being looked up
@ -64,7 +64,7 @@ contrapositive : ∀ {ℓ₁ ℓ₂} {P : Set ℓ₁} {Q : Set ℓ₂} → (P
contrapositive p→q ¬q p = ¬q (p→q p)
\end{code}
Using the above, we can decide equality of two identifiers
Using the above, we can decide equality of two identifiers
by deciding equality on the underlying strings.
\begin{code}
@ -143,6 +143,12 @@ function that behaves like the desired map.
We define handy abbreviations for updating a map two, three, or four times.
<div class="note hidden">
Wen: you don't actually need to define these, you can simply declare `_,_↦_` to
be a left-associative infix operator with an `infixl` statement, and then you'll
be able to just evaluate `M , x ↦ y , z ↦ w` as `(M , x ↦ y) , z ↦ w`.
</div>
\begin{code}
_,_↦_,_↦_ : ∀ {A} → TotalMap A → Id → A → Id → A → TotalMap A
ρ , x₁ ↦ v₁ , x₂ ↦ v₂ = (ρ , x₁ ↦ v₁), x₂ ↦ v₂
@ -180,7 +186,7 @@ application!
To use maps in later chapters, we'll need several fundamental
facts about how they behave. Even if you don't work the following
exercises, make sure you understand the statements of
the lemmas!
the lemmas!
#### Exercise: 1 star, optional (apply-empty)
First, the empty map returns its default element for all keys:
@ -290,25 +296,65 @@ updates.
\begin{code}
update-permute : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A) (y : Id) (w : A) (z : Id)
→ x ≢ y → (ρ , x ↦ v , y ↦ w) z ≡ (ρ , y ↦ w , x ↦ v) z
update-permute {A} ρ x v y w z x≢y with x ≟ z | y ≟ z
... | yes x≡z | yes y≡z = ⊥-elim (x≢y (trans x≡z (sym y≡z)))
... | no x≢z | yes y≡z rewrite y≡z = {! sym (update-eq ρ z w)!}
... | yes x≡z | no y≢z rewrite x≡z = {! update-eq ρ z v!}
... | no x≢z | no y≢z = {! trans (update-neq ρ y w z y≢z) (sym (update-neq ρ x v z x≢z))!}
{-
Holes are typed as follows. What do the "| z ≟ z" mean, and how can I deal with them?
Why does "λ y₁" appear in the final hole?
?0 : w ≡ ((ρ , z ↦ w) z | z ≟ z)
?1 : ((ρ , z ↦ v) z | z ≟ z) ≡ v
?2 : (((λ y₁ → (ρ , x ↦ v) y₁ | x ≟ y₁) , y ↦ w) z | no y≢z) ≡
(((λ y₁ → (ρ , y ↦ w) y₁ | y ≟ y₁) , x ↦ v) z | no x≢z)
-}
update-permute {A} ρ x v y w z x≢y
with x ≟ z | y ≟ z
update-permute {A} ρ x v y w z x≢y
| yes x≡z | yes y≡z = ⊥-elim (x≢y (trans x≡z (sym y≡z)))
update-permute {A} ρ x v y w z x≢y
| no x≢z | yes y≡z rewrite y≡z
with z ≟ z
update-permute {A} ρ x v y w z x≢y
| no x≢z | yes y≡z | yes z≡z = refl
update-permute {A} ρ x v y w z x≢y
| no x≢z | yes y≡z | no z≢z = ⊥-elim (z≢z refl)
update-permute {A} ρ x v y w z x≢y
| yes x≡z | no y≢z rewrite x≡z
with z ≟ z
update-permute {A} ρ x v y w z x≢y
| yes x≡z | no y≢z | yes z≡z = refl
update-permute {A} ρ x v y w z x≢y
| yes x≡z | no y≢z | no z≢z = ⊥-elim (z≢z refl)
update-permute {A} ρ x v y w z x≢y
| no x≢z | no y≢z
with x ≟ z | y ≟ z
update-permute {A} ρ x v y w z x≢y
| no _ | no _ | no x≢z | no y≢z
= refl
update-permute {A} ρ x v y w z x≢y
| no x≢z | no y≢z | yes x≡z | _
= ⊥-elim (x≢z x≡z)
update-permute {A} ρ x v y w z x≢y
| no x≢z | no y≢z | _ | yes y≡z
= ⊥-elim (y≢z y≡z)
\end{code}
</div>
<div class="note hidden">
Phil:
Holes are typed as follows. What do the "| z ≟ z" mean, and how can I deal
with them? Why does "λ y₁" appear in the final hole?
?0 : w ≡ ((ρ , z ↦ w) z | z ≟ z)
?1 : ((ρ , z ↦ v) z | z ≟ z) ≡ v
?2 : (((λ y₁ → (ρ , x ↦ v) y₁ | x ≟ y₁) , y ↦ w) z | no y≢z) ≡
(((λ y₁ → (ρ , y ↦ w) y₁ | y ≟ y₁) , x ↦ v) z | no x≢z)
Wen:
The "| z ≟ z" term appears because there is a comparison on the two strings z
and z somewhere in the code. Because the decidable equality (and in fact all
functions on strings) are postulate, they do not reduce during type checking.
In order to stop this, you would have to insert a with clause at the location
where you want the term to reduce, i.e. "with z ≟ z", so that you can cover
both possible outputs, even if you already know that "z ≡ z", e.g. due to
reflexivity. You can cover the other case with a ⊥-elim fairly easily, but
it's not pretty. This is why I used naturals, because their equality test is
implemented in Agda and therefore can reduce. However, I'm not sure if
switching would in fact solve this problem, due to the fact that we're dealing
with variables, but I think so. See the completed code above for the
not-so-pretty way of actually implementing update-permute'.
</div>
## Partial maps
Finally, we define _partial maps_ on top of total maps. A partial

View file

@ -1,722 +0,0 @@
---
title : "StlcOld: The Simply Typed Lambda-Calculus (Old)"
layout : page
permalink : /StlcOld
---
<div class="foldable">
\begin{code}
open import Maps using (Id; id; _≟_; PartialMap; module PartialMap)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Maybe using (Maybe; just; nothing)
open import Data.Nat using (; suc; zero; _+_)
open import Data.Product using (∃; ∄; _,_)
open import Function using (_∘_; _$_)
open import Relation.Nullary using (Dec; yes; no)
open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl)
\end{code}
</div>
The simply typed lambda-calculus (STLC) is a tiny core
calculus embodying the key concept of _functional abstraction_,
which shows up in pretty much every real-world programming
language in some form (functions, procedures, methods, etc.).
We will follow exactly the same pattern as in the previous chapter
when formalizing this calculus (syntax, small-step semantics,
typing rules) and its main properties (progress and preservation).
The new technical challenges arise from the mechanisms of
_variable binding_ and _substitution_. It which will take some
work to deal with these.
## Overview
The STLC is built on some collection of _base types_:
booleans, numbers, strings, etc. The exact choice of base types
doesn't matter much---the construction of the language and its
theoretical properties work out the same no matter what we
choose---so for the sake of brevity let's take just $$bool$$ for
the moment. At the end of the chapter we'll see how to add more
base types, and in later chapters we'll enrich the pure STLC with
other useful constructs like pairs, records, subtyping, and
mutable state.
Starting from boolean constants and conditionals, we add three
things:
- variables
- function abstractions
- application
This gives us the following collection of abstract syntax
constructors (written out first in informal BNF notation---we'll
formalize it below).
$$
\begin{array}{rll}
\text{Terms}\;s,t,u
::= & x & \text{variable} \\
\mid & \lambda x : A . t & \text{abstraction} \\
\mid & s\;t & \text{application} \\
\mid & true & \text{constant true} \\
\mid & false & \text{constant false} \\
\mid & \text{if }s\text{ then }t\text{ else }u & \text{conditional}
\end{array}
$$
In a lambda abstraction $$\lambda x : A . t$$, the variable $$x$$ is called the
_parameter_ to the function; the term $$t$$ is its _body_. The annotation $$:A$$
specifies the type of arguments that the function can be applied to.
Some examples:
- The identity function for booleans:
$$\lambda x:bool. x$$.
- The identity function for booleans, applied to the boolean $$true$$:
$$(\lambda x:bool. x)\;true$$.
- The boolean "not" function:
$$\lambda x:bool. \text{if }x\text{ then }false\text{ else }true$$.
- The constant function that takes every (boolean) argument to $$true$$:
$$\lambda x:bool. true$$.
- A two-argument function that takes two booleans and returns the
first one:
$$\lambda x:bool. \lambda y:bool. x$$.
As in Agda, a two-argument function is really a
one-argument function whose body is also a one-argument function.
- A two-argument function that takes two booleans and returns the
first one, applied to the booleans $$false$$ and $$true$$:
$$(\lambda x:bool. \lambda y:bool. x)\;false\;true$$.
As in Agda, application associates to the left---i.e., this
expression is parsed as
$$((\lambda x:bool. \lambda y:bool. x)\;false)\;true$$.
- A higher-order function that takes a _function_ $$f$$ (from booleans
to booleans) as an argument, applies $$f$$ to $$true$$, and applies
$$f$$ again to the result:
$$\lambda f:bool\rightarrow bool. f\;(f\;true)$$.
- The same higher-order function, applied to the constantly $$false$$
function:
$$(\lambda f:bool\rightarrow bool. f\;(f\;true))\;(\lambda x:bool. false)$$.
As the last several examples show, the STLC is a language of
_higher-order_ functions: we can write down functions that take
other functions as arguments and/or return other functions as
results.
The STLC doesn't provide any primitive syntax for defining _named_
functions---all functions are "anonymous." We'll see in chapter
`MoreStlc` that it is easy to add named functions to what we've
got---indeed, the fundamental naming and binding mechanisms are
exactly the same.
The _types_ of the STLC include $$bool$$, which classifies the
boolean constants $$true$$ and $$false$$ as well as more complex
computations that yield booleans, plus _arrow types_ that classify
functions.
$$
\text{Types}\;A,B ::= bool \mid A \rightarrow B
$$
For example:
- $$\lambda x:bool. false$$ has type $$bool\rightarrow bool$$;
- $$\lambda x:bool. x$$ has type $$bool\rightarrow bool$$;
- $$(\lambda x:bool. x)\;true$$ has type $$bool$$;
- $$\lambda x:bool. \lambda y:bool. x$$ has type
$$bool\rightarrow bool\rightarrow bool$$
(i.e., $$bool\rightarrow (bool\rightarrow bool)$$)
- $$(\lambda x:bool. \lambda y:bool. x)\;false$$ has type $$bool\rightarrow bool$$
- $$(\lambda x:bool. \lambda y:bool. x)\;false\;true$$ has type $$bool$$
## Syntax
We begin by formalizing the syntax of the STLC.
Unfortunately, $$\rightarrow$$ is already used for Agda's function type,
so we will STLC's function type as `_⇒_`.
### Types
\begin{code}
data Type : Set where
bool : Type
_⇒_ : Type → Type → Type
infixr 5 _⇒_
\end{code}
### Terms
\begin{code}
data Term : Set where
var : Id → Term
app : Term → Term → Term
abs : Id → Type → Term → Term
true : Term
false : Term
if_then_else_ : Term → Term → Term → Term
\end{code}
<div class="hidden">
\begin{code}
infixr 8 if_then_else_
\end{code}
</div>
Note that an abstraction $$\lambda x:A.t$$ (formally, `abs x A t`) is
always annotated with the type $$A$$ of its parameter, in contrast
to Agda (and other functional languages like ML, Haskell, etc.),
which use _type inference_ to fill in missing annotations. We're
not considering type inference here.
We introduce $$x, y, z$$ as names for variables. The pragmas ensure
that $$id 0, id 1, id 2$$ display as $$x, y, z$$.
\begin{code}
x = id 0
y = id 1
z = id 2
{-# DISPLAY id zero = x #-}
{-# DISPLAY id (suc zero) = y #-}
{-# DISPLAY id (suc (suc zero)) = z #-}
\end{code}
Some examples...
$$\text{idB} = \lambda x:bool. x$$.
\begin{code}
idB = (abs x bool (var x))
\end{code}
$$\text{idBB} = \lambda x:bool\rightarrow bool. x$$.
\begin{code}
idBB = (abs x (bool ⇒ bool) (var x))
\end{code}
$$\text{idBBBB} = \lambda x:(bool\rightarrow bool)\rightarrow (bool\rightarrow bool). x$$.
\begin{code}
idBBBB = (abs x ((bool ⇒ bool) ⇒ (bool ⇒ bool)) (var x))
\end{code}
$$\text{k} = \lambda x:bool. \lambda y:bool. x$$.
\begin{code}
k = (abs x bool (abs y bool (var x)))
\end{code}
$$\text{notB} = \lambda x:bool. \text{if }x\text{ then }false\text{ else }true$$.
\begin{code}
notB = (abs x bool (if (var x) then false else true))
\end{code}
<div class="hidden">
\begin{code}
{-# DISPLAY abs 0 bool (var 0) = idB #-}
{-# DISPLAY abs 0 (bool ⇒ bool) (var 0) = idBB #-}
{-# DISPLAY abs 0 ((bool ⇒ bool) ⇒ (bool ⇒ bool)) (var 0) = idBBBB #-}
{-# DISPLAY abs 0 bool (abs y bool (var 0)) = k #-}
{-# DISPLAY abs 0 bool (if (var 0) then false else true) = notB #-}
\end{code}
</div>
## Operational Semantics
To define the small-step semantics of STLC terms, we begin,
as always, by defining the set of values. Next, we define the
critical notions of _free variables_ and _substitution_, which are
used in the reduction rule for application expressions. And
finally we give the small-step relation itself.
### Values
To define the values of the STLC, we have a few cases to consider.
First, for the boolean part of the language, the situation is
clear: $$true$$ and $$false$$ are the only values. An $$\text{if}$$
expression is never a value.
Second, an application is clearly not a value: It represents a
function being invoked on some argument, which clearly still has
work left to do.
Third, for abstractions, we have a choice:
- We can say that $$\lambda x:A. t$$ is a value only when $$t$$ is a
value---i.e., only if the function's body has been
reduced (as much as it can be without knowing what argument it
is going to be applied to).
- Or we can say that $$\lambda x:A. t$$ is always a value, no matter
whether $$t$$ is one or not---in other words, we can say that
reduction stops at abstractions.
Agda makes the first choice---for example,
\begin{code}
test_normalizeUnderLambda : (λ (x : ) → 3 + 4) ≡ (λ (x : ) → 7)
test_normalizeUnderLambda = refl
\end{code}
Most real-world functional programming languages make the second
choice---reduction of a function's body only begins when the
function is actually applied to an argument. We also make the
second choice here.
\begin{code}
data Value : Term → Set where
abs : ∀ {x A t}
→ Value (abs x A t)
true : Value true
false : Value false
\end{code}
Finally, we must consider what constitutes a _complete_ program.
Intuitively, a "complete program" must not refer to any undefined
variables. We'll see shortly how to define the _free_ variables
in a STLC term. A complete program is _closed_---that is, it
contains no free variables.
Having made the choice not to reduce under abstractions, we don't
need to worry about whether variables are values, since we'll
always be reducing programs "from the outside in," and that means
the small-step relation will always be working with closed terms.
### Substitution
Now we come to the heart of the STLC: the operation of
substituting one term for a variable in another term. This
operation is used below to define the operational semantics of
function application, where we will need to substitute the
argument term for the function parameter in the function's body.
For example, we reduce
$$(\lambda x:bool. \text{if }x\text{ then }true\text{ else }x)\;false$$
to
$$\text{if }false\text{ then }true\text{ else }false$$
by substituting $$false$$ for the parameter $$x$$ in the body of the
function.
In general, we need to be able to substitute some given term $$s$$
for occurrences of some variable $$x$$ in another term $$t$$. In
informal discussions, this is usually written $$[x:=s]t$$ and
pronounced "substitute $$x$$ with $$s$$ in $$t$$."
Here are some examples:
- $$[x:=true](\text{if }x\text{ then }x\text{ else }false)$$
yields $$\text{if }true\text{ then }true\text{ else }false$$
- $$[x:=true]x$$
yields $$true$$
- $$[x:=true](\text{if }x\text{ then }x\text{ else }y)$$
yields $$\text{if }true\text{ then }true\text{ else }y$$
- $$[x:=true]y$$
yields $$y$$
- $$[x:=true]false$$
yields $$false$$ (vacuous substitution)
- $$[x:=true](\lambda y:bool. \text{if }y\text{ then }x\text{ else }false)$$
yields $$\lambda y:bool. \text{if }y\text{ then }true\text{ else }false$$
- $$[x:=true](\lambda y:bool. x)$$
yields $$\lambda y:bool. true$$
- $$[x:=true](\lambda y:bool. y)$$
yields $$\lambda y:bool. y$$
- $$[x:=true](\lambda x:bool. x)$$
yields $$\lambda x:bool. x$$
The last example is very important: substituting $$x$$ with $$true$$ in
$$\lambda x:bool. x$$ does _not_ yield $$\lambda x:bool. true$$! The reason for
this is that the $$x$$ in the body of $$\lambda x:bool. x$$ is _bound_ by the
abstraction: it is a new, local name that just happens to be
spelled the same as some global name $$x$$.
Here is the definition, informally...
$$
\begin{aligned}
&[x:=s]x &&= s \\
&[x:=s]y &&= y \;\{\text{if }x\neq y\} \\
&[x:=s](\lambda x:A. t) &&= \lambda x:A. t \\
&[x:=s](\lambda y:A. t) &&= \lambda y:A. [x:=s]t \;\{\text{if }x\neq y\} \\
&[x:=s](t1\;t2) &&= ([x:=s]t1) ([x:=s]t2) \\
&[x:=s]true &&= true \\
&[x:=s]false &&= false \\
&[x:=s](\text{if }t1\text{ then }t2\text{ else }t3) &&=
\text{if }[x:=s]t1\text{ then }[x:=s]t2\text{ else }[x:=s]t3
\end{aligned}
$$
... and formally:
\begin{code}
[_:=_]_ : Id -> Term -> Term -> Term
[ x := v ] (var y) with x ≟ y
... | yes x=y = v
... | no x≠y = var y
[ x := v ] (app s t) = app ([ x := v ] s) ([ x := v ] t)
[ x := v ] (abs y A t) with x ≟ y
... | yes x=y = abs y A t
... | no x≠y = abs y A ([ x := v ] t)
[ x := v ] true = true
[ x := v ] false = false
[ x := v ] (if s then t else u) =
if [ x := v ] s then [ x := v ] t else [ x := v ] u
\end{code}
<div class="hidden">
\begin{code}
infix 9 [_:=_]_
\end{code}
</div>
_Technical note_: Substitution becomes trickier to define if we
consider the case where $$s$$, the term being substituted for a
variable in some other term, may itself contain free variables.
Since we are only interested here in defining the small-step relation
on closed terms (i.e., terms like $$\lambda x:bool. x$$ that include
binders for all of the variables they mention), we can avoid this
extra complexity here, but it must be dealt with when formalizing
richer languages.
#### Exercise: 3 stars (subst-correct)
The definition that we gave above defines substitution as a _function_.
Suppose, instead, we wanted to define substitution as an inductive _relation_.
We've begun the definition by providing the `data` header and
one of the constructors; your job is to fill in the rest of the constructors
and prove that the relation you've defined coincides with the function given
above.
\begin{code}
data [_:=_]_==>_ (x : Id) (s : Term) : Term -> Term -> Set where
var1 : [ x := s ] (var x) ==> s
{- FILL IN HERE -}
\end{code}
\begin{code}
postulate
subst-correct : ∀ s x t t'
→ [ x := s ] t ≡ t'
→ [ x := s ] t ==> t'
\end{code}
### Reduction
The small-step reduction relation for STLC now follows the
same pattern as the ones we have seen before. Intuitively, to
reduce a function application, we first reduce its left-hand
side (the function) until it becomes an abstraction; then we
reduce its right-hand side (the argument) until it is also a
value; and finally we substitute the argument for the bound
variable in the body of the abstraction. This last rule, written
informally as
$$
(\lambda x : A . t) v \Longrightarrow [x:=v]t
$$
is traditionally called "beta-reduction".
$$
\begin{array}{cl}
\frac{value(v)}{(\lambda x : A . t) v \Longrightarrow [x:=v]t}&(red)\\\\
\frac{s \Longrightarrow s'}{s\;t \Longrightarrow s'\;t}&(app1)\\\\
\frac{value(v)\quad t \Longrightarrow t'}{v\;t \Longrightarrow v\;t'}&(app2)
\end{array}
$$
... plus the usual rules for booleans:
$$
\begin{array}{cl}
\frac{}{(\text{if }true\text{ then }t_1\text{ else }t_2) \Longrightarrow t_1}&(iftrue)\\\\
\frac{}{(\text{if }false\text{ then }t_1\text{ else }t_2) \Longrightarrow t_2}&(iffalse)\\\\
\frac{s \Longrightarrow s'}{\text{if }s\text{ then }t_1\text{ else }t_2
\Longrightarrow \text{if }s\text{ then }t_1\text{ else }t_2}&(if)
\end{array}
$$
Formally:
\begin{code}
data _==>_ : Term → Term → Set where
red : ∀ {x A s t}
→ Value t
→ app (abs x A s) t ==> [ x := t ] s
app1 : ∀ {s s' t}
→ s ==> s'
→ app s t ==> app s' t
app2 : ∀ {s t t'}
→ Value s
→ t ==> t'
→ app s t ==> app s t'
if : ∀ {s s' t u}
→ s ==> s'
→ if s then t else u ==> if s' then t else u
iftrue : ∀ {s t}
→ if true then s else t ==> s
iffalse : ∀ {s t}
→ if false then s else t ==> t
\end{code}
<div class="hidden">
\begin{code}
infix 1 _==>_
\end{code}
</div>
\begin{code}
data Multi (R : Term → Term → Set) : Term → Term → Set where
refl : ∀ {x} -> Multi R x x
step : ∀ {x y z} -> R x y -> Multi R y z -> Multi R x z
\end{code}
\begin{code}
_==>*_ : Term → Term → Set
_==>*_ = Multi _==>_
\end{code}
<div class="hidden">
\begin{code}
{-# DISPLAY Multi _==>_ = _==>*_ #-}
\end{code}
</div>
### Examples
Example:
$$((\lambda x:bool\rightarrow bool. x) (\lambda x:bool. x)) \Longrightarrow^* (\lambda x:bool. x)$$.
\begin{code}
step-example1 : (app idBB idB) ==>* idB
step-example1 = step (red abs)
$ refl
\end{code}
Example:
$$(\lambda x:bool\rightarrow bool. x) \;((\lambda x:bool\rightarrow bool. x)\;(\lambda x:bool. x))) \Longrightarrow^* (\lambda x:bool. x)$$.
\begin{code}
step-example2 : (app idBB (app idBB idB)) ==>* idB
step-example2 = step (app2 abs (red abs))
$ step (red abs)
$ refl
\end{code}
Example:
$$((\lambda x:bool\rightarrow bool. x)\;(\lambda x:bool. \text{if }x\text{ then }false\text{ else }true))\;true\Longrightarrow^* false$$.
\begin{code}
step-example3 : (app (app idBB notB) true) ==>* false
step-example3 = step (app1 (red abs))
$ step (red true)
$ step iftrue
$ refl
\end{code}
Example:
$$((\lambda x:bool\rightarrow bool. x)\;((\lambda x:bool. \text{if }x\text{ then }false\text{ else }true)\;true))\Longrightarrow^* false$$.
\begin{code}
step-example4 : (app idBB (app notB true)) ==>* false
step-example4 = step (app2 abs (red true))
$ step (app2 abs iftrue)
$ step (red false)
$ refl
\end{code}
#### Exercise: 2 stars (step-example5)
\begin{code}
postulate
step-example5 : (app (app idBBBB idBB) idB) ==>* idB
\end{code}
## Typing
Next we consider the typing relation of the STLC.
### Contexts
_Question_: What is the type of the term "$$x\;y$$"?
_Answer_: It depends on the types of $$x$$ and $$y$$!
I.e., in order to assign a type to a term, we need to know
what assumptions we should make about the types of its free
variables.
This leads us to a three-place _typing judgment_, informally
written $$\Gamma\vdash t : A$$, where $$\Gamma$$ is a
"typing context"---a mapping from variables to their types.
Informally, we'll write $$\Gamma , x:A$$ for "extend the partial function
$$\Gamma$$ to also map $$x$$ to $$A$$." Formally, we use the function `_,__`
(or "update") to add a binding to a context.
\begin{code}
Ctxt : Set
Ctxt = PartialMap Type
∅ : Ctxt
∅ = PartialMap.empty
_,__ : Ctxt -> Id -> Type -> Ctxt
_,__ = PartialMap.update
\end{code}
<div class="hidden">
\begin{code}
infixl 3 _,__
\end{code}
</div>
### Typing Relation
$$
\begin{array}{cl}
\frac{\Gamma\;x = A}{\Gamma\vdash{x:A}}&(var)\\\\
\frac{\Gamma,x:A\vdash t:B}{\Gamma\vdash (\lambda x:A.t) : A\rightarrow B}&(abs)\\\\
\frac{\Gamma\vdash s:A\rightarrow B\quad\Gamma\vdash t:A}{\Gamma\vdash (s\;t) : B}&(app)\\\\
\frac{}{\Gamma\vdash true : bool}&(true)\\\\
\frac{}{\Gamma\vdash false : bool}&(true)\\\\
\frac{\Gamma\vdash s:bool \quad \Gamma\vdash t1:A \quad \Gamma\vdash t2:A}{\Gamma\vdash\text{if }s\text{ then }t1\text{ else }t2 : A}&(if)
\end{array}
$$
We can read the three-place relation $$\Gamma\vdash (t : A)$$ as:
"to the term $$t$$ we can assign the type $$A$$ using as types for
the free variables of $$t$$ the ones specified in the context
$$\Gamma$$."
\begin{code}
data _⊢__ : Ctxt -> Term -> Type -> Set where
var : ∀ {Γ} x {A}
→ Γ x ≡ just A
→ Γ ⊢ var x A
abs : ∀ {Γ} {x} {A} {B} {s}
→ Γ , x A ⊢ s B
→ Γ ⊢ abs x A s A ⇒ B
app : ∀ {Γ} {A} {B} {s} {t}
→ Γ ⊢ s A ⇒ B
→ Γ ⊢ t A
→ Γ ⊢ app s t B
true : ∀ {Γ}
→ Γ ⊢ true bool
false : ∀ {Γ}
→ Γ ⊢ false bool
if_then_else_ : ∀ {Γ} {s} {t} {u} {A}
→ Γ ⊢ s bool
→ Γ ⊢ t A
→ Γ ⊢ u A
→ Γ ⊢ if s then t else u A
\end{code}
<div class="hidden">
\begin{code}
infix 1 _⊢__
\end{code}
</div>
### Examples
\begin{code}
typing-example1 : ∅ ⊢ idB bool ⇒ bool
typing-example1 = abs (var x refl)
\end{code}
Another example:
$$\varnothing\vdash \lambda x:A. \lambda y:A\rightarrow A. y\;(y\;x) : A\rightarrow (A\rightarrow A)\rightarrow A$$.
\begin{code}
typing-example2 : ∅ ⊢
(abs x bool
(abs y (bool ⇒ bool)
(app (var y)
(app (var y) (var x)))))
(bool ⇒ (bool ⇒ bool) ⇒ bool)
typing-example2 =
(abs
(abs
(app (var y refl)
(app (var y refl) (var x refl) ))))
\end{code}
#### Exercise: 2 stars (typing-example3)
Formally prove the following typing derivation holds:
$$\exists A, \varnothing\vdash \lambda x:bool\rightarrow B. \lambda y:bool\rightarrow bool. \lambda z:bool. y\;(x\;z) : A$$.
\begin{code}
postulate
typing-example3 : ∃ λ A → ∅ ⊢
(abs x (bool ⇒ bool)
(abs y (bool ⇒ bool)
(abs z bool
(app (var y) (app (var x) (var z)))))) A
\end{code}
We can also show that terms are _not_ typable. For example, let's
formally check that there is no typing derivation assigning a type
to the term $$\lambda x:bool. \lambda y:bool. x\;y$$---i.e.,
$$\nexists A, \varnothing\vdash \lambda x:bool. \lambda y:bool. x\;y : A$$.
\begin{code}
postulate
typing-nonexample1 : ∄ λ A → ∅ ⊢
(abs x bool
(abs y bool
(app (var x) (var y)))) A
\end{code}
#### Exercise: 3 stars, optional (typing-nonexample2)
Another nonexample:
$$\nexists A, \exists B, \varnothing\vdash \lambda x:A. x\;x : B$$.
\begin{code}
postulate
typing-nonexample2 : ∄ λ A → ∃ λ B → ∅ ⊢
(abs x B (app (var x) (var x))) A
\end{code}