lambda calc post
This commit is contained in:
parent
42cbda6ae1
commit
1f454d6883
4 changed files with 156 additions and 45 deletions
|
@ -4,7 +4,7 @@ import sitemap from "@astrojs/sitemap";
|
||||||
import { rehypeAccessibleEmojis } from "rehype-accessible-emojis";
|
import { rehypeAccessibleEmojis } from "rehype-accessible-emojis";
|
||||||
|
|
||||||
import remarkReadingTime from "./plugin/remark-reading-time";
|
import remarkReadingTime from "./plugin/remark-reading-time";
|
||||||
import emoji from "remark-emoji";
|
import remarkEmoji from "remark-emoji";
|
||||||
import remarkMermaid from "astro-diagram/remark-mermaid";
|
import remarkMermaid from "astro-diagram/remark-mermaid";
|
||||||
import remarkDescription from "astro-remark-description";
|
import remarkDescription from "astro-remark-description";
|
||||||
import remarkAdmonitions from "./plugin/remark-admonitions";
|
import remarkAdmonitions from "./plugin/remark-admonitions";
|
||||||
|
@ -26,12 +26,12 @@ export default defineConfig({
|
||||||
syntaxHighlight: "shiki",
|
syntaxHighlight: "shiki",
|
||||||
shikiConfig: { theme: "css-variables" },
|
shikiConfig: { theme: "css-variables" },
|
||||||
remarkPlugins: [
|
remarkPlugins: [
|
||||||
|
remarkMath,
|
||||||
remarkAdmonitions,
|
remarkAdmonitions,
|
||||||
remarkReadingTime,
|
remarkReadingTime,
|
||||||
remarkTypst,
|
remarkTypst,
|
||||||
[remarkMath, {}],
|
|
||||||
remarkMermaid,
|
remarkMermaid,
|
||||||
emoji,
|
remarkEmoji,
|
||||||
[remarkDescription, { name: "excerpt" }],
|
[remarkDescription, { name: "excerpt" }],
|
||||||
],
|
],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
|
|
|
@ -16,13 +16,13 @@ export default remarkAdmonitions;
|
||||||
|
|
||||||
const handleNode = (config: Config): BuildVisitor => (node) => {
|
const handleNode = (config: Config): BuildVisitor => (node) => {
|
||||||
// Filter required elems
|
// Filter required elems
|
||||||
if (node.type != "blockquote") return;
|
if (node.type !== "blockquote") return;
|
||||||
const blockquote = node as Blockquote;
|
const blockquote = node as Blockquote;
|
||||||
|
|
||||||
if (blockquote.children[0]?.type != "paragraph") return;
|
if (blockquote.children[0]?.type !== "paragraph") return;
|
||||||
|
|
||||||
const paragraph = blockquote.children[0];
|
const paragraph = blockquote.children[0];
|
||||||
if (paragraph.children[0]?.type != "text") return;
|
if (paragraph.children[0]?.type !== "text") return;
|
||||||
|
|
||||||
const text = paragraph.children[0];
|
const text = paragraph.children[0];
|
||||||
|
|
||||||
|
@ -139,8 +139,8 @@ type ClassNameMap = ClassNames | ((title: string) => ClassNames);
|
||||||
|
|
||||||
export function classNameMap(gen: ClassNameMap) {
|
export function classNameMap(gen: ClassNameMap) {
|
||||||
return (title: string) => {
|
return (title: string) => {
|
||||||
const classNames = typeof gen == "function" ? gen(title) : gen;
|
const classNames = typeof gen === "function" ? gen(title) : gen;
|
||||||
return typeof classNames == "object" ? classNames.join(" ") : classNames;
|
return typeof classNames === "object" ? classNames.join(" ") : classNames;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +148,8 @@ type NameFilter = ((title: string) => boolean) | string[];
|
||||||
|
|
||||||
export function nameFilter(filter: NameFilter) {
|
export function nameFilter(filter: NameFilter) {
|
||||||
return (title: string) => {
|
return (title: string) => {
|
||||||
return typeof filter == "function" ? filter(title) : filter.includes(title);
|
return typeof filter === "function"
|
||||||
|
? filter(title)
|
||||||
|
: filter.includes(title);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
145
src/content/posts/2024-04-04-lambda-calculus.md
Normal file
145
src/content/posts/2024-04-04-lambda-calculus.md
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
---
|
||||||
|
title: The Lambda Calculus
|
||||||
|
date: 2024-04-04T21:45:28.264
|
||||||
|
draft: true
|
||||||
|
toc: true
|
||||||
|
languages: ["typst"]
|
||||||
|
tags: ["typst"]
|
||||||
|
---
|
||||||
|
|
||||||
|
The lambda calculus is an abstract machine for modeling computation. In this
|
||||||
|
tutorial I will build up the lambda calculus from scratch.
|
||||||
|
|
||||||
|
## Expressions
|
||||||
|
|
||||||
|
Let's start with expressions. You've probably encountered these in math class.
|
||||||
|
They look like things like:
|
||||||
|
|
||||||
|
- $3$
|
||||||
|
- $5 \times 5$
|
||||||
|
- $2\sqrt{12} - 5i$
|
||||||
|
|
||||||
|
Some of these probably look like they can be simplified. That's fine! We're not
|
||||||
|
worried about that yet. The computation aspect will come in a bit.
|
||||||
|
|
||||||
|
### Expression Trees
|
||||||
|
|
||||||
|
The important thing here is that all of these have some tree-like structure. For
|
||||||
|
example, look at $5 \times 5$:
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#import "@preview/fletcher:0.4.3" as fletcher: *
|
||||||
|
#set page(width: auto, height: auto, margin: (x: 0.25pt, y: 0.25pt))
|
||||||
|
#set text(18pt)
|
||||||
|
#diagram(cell-size: 0.5cm, $
|
||||||
|
& times edge("dl", ->) edge("dr", ->) \
|
||||||
|
5 & & 5 \
|
||||||
|
$)
|
||||||
|
```
|
||||||
|
|
||||||
|
And that last one, $2\sqrt{12} - 5i$:
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#import "@preview/fletcher:0.4.3" as fletcher: *
|
||||||
|
#import math
|
||||||
|
#set page(width: auto, height: auto, margin: (x: 0.5em, y: 0.5em))
|
||||||
|
#set text(18pt)
|
||||||
|
#diagram(cell-size: 0.5cm, {
|
||||||
|
node(pos: (0, 0), label: $-$)
|
||||||
|
node(pos: (-1, 1), label: $times$)
|
||||||
|
node(pos: (1, 1), label: $times$)
|
||||||
|
edge((0, 0), (-1, 1))
|
||||||
|
edge((0, 0), (1, 1))
|
||||||
|
node(pos: (-1.5, 2), label: $2$)
|
||||||
|
node(pos: (-0.5, 2), label: $math.sqrt(...)$)
|
||||||
|
node(pos: (-0.5, 3), label: $12$)
|
||||||
|
edge((-1, 1), (-1.5, 2))
|
||||||
|
edge((-1, 1), (-0.5, 2))
|
||||||
|
edge((-0.5, 2), (-0.5, 3))
|
||||||
|
node(pos: (0.5, 2), label: $5$)
|
||||||
|
node(pos: (1.5, 2), label: $i$)
|
||||||
|
edge((1, 1), (0.5, 2))
|
||||||
|
edge((1, 1), (1.5, 2))
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
These follow the order of operations (also known as PEMDAS). They tell you that
|
||||||
|
_if_ you were going to evaluate this, you would want to apply it in this
|
||||||
|
fashion.
|
||||||
|
|
||||||
|
If you look at each point in the tree, you might notice that there's several different types of branches:
|
||||||
|
|
||||||
|
- Numbers, like $2$, $5$, or $12$ don't have any children
|
||||||
|
- The square root function, $\sqrt{...}$ has 1 child
|
||||||
|
- The subtraction ($-$) and multiplication ($\times$) functions have 2 children
|
||||||
|
|
||||||
|
The important thing to us is to define a **language** for expressions. This
|
||||||
|
way, we know exactly what kinds of expressions we can build. Let's take the
|
||||||
|
few operations in the list above and turn it into a **language** for writing
|
||||||
|
expressions:
|
||||||
|
|
||||||
|
$$
|
||||||
|
e ::= n \mid \sqrt{e} \mid e - e \mid e \times e
|
||||||
|
$$
|
||||||
|
|
||||||
|
We call these **constructors** of the expression. The notation is a bit dense,
|
||||||
|
but this essentially means $e$, which is shorthand for _expression_, is defined
|
||||||
|
to be either of ($|$):
|
||||||
|
|
||||||
|
- $n$, which is just a convention meaning "any number"
|
||||||
|
- $\sqrt{e}$, which means "square root of another expression"
|
||||||
|
- $e - e$ and $e \times e$, which correspond to subtraction and multiplication respectively
|
||||||
|
|
||||||
|
If you look closely, the number of $e$s in each option corresponds exactly to
|
||||||
|
the number of children it had in the expression tree.
|
||||||
|
|
||||||
|
Let's write down an expression language for the lambda calculus. In its simplest form, it looks like this:
|
||||||
|
|
||||||
|
$$
|
||||||
|
e ::= x \mid \lambda x.e \mid e\; e
|
||||||
|
$$
|
||||||
|
|
||||||
|
Here, $x$ is a convention that stands for "some variable". Without knowing what any of this means, we can already start putting together some expressions:
|
||||||
|
|
||||||
|
- $\lambda x.x$
|
||||||
|
- $\lambda s.(\lambda z.(s\; z))$
|
||||||
|
|
||||||
|
As an exercise, try drawing some of the expression trees that correspond to
|
||||||
|
these expressions. Once you're familiar enough with how expressions are built
|
||||||
|
syntactically, we can talk about evaluation.
|
||||||
|
|
||||||
|
## Evaluation
|
||||||
|
|
||||||
|
The expression language we just defined is typically considered the _statics_ of
|
||||||
|
the language. It defines how we can write down the language. What we're going to
|
||||||
|
talk about now is the _dynamics_, or how it's evaluated.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Semantics vs. Implementation</summary>
|
||||||
|
|
||||||
|
At this point it's probably a good idea to make a note about _semantics_ vs. _implementation_.
|
||||||
|
|
||||||
|
Semantics describe the outcome. If my arithmetic language defines
|
||||||
|
multiplication's _semantics_ it would require that multiplication of two numbers
|
||||||
|
to achieve another number that has some certain properties, like "repeatedly
|
||||||
|
subtracting the first number the same number of times as the second number
|
||||||
|
produces 0."
|
||||||
|
|
||||||
|
Implementation, on the other hand, needs to conform to the semantics. If I asked
|
||||||
|
you to compute $15 \times 16$ by hand, you'd probably bust out some pencil and
|
||||||
|
paper and do some long form multiplication, where you'd compute a couple of
|
||||||
|
intermediate results and add them, getting $240$.
|
||||||
|
|
||||||
|
A computer, on the other hand, notices $16 = 10000_2$, and just shifts $15 =
|
||||||
|
0111_2$ over by 4 bits, to get $01110000_2 = 240$. The ways that this same
|
||||||
|
result was computed were different, but they achieved the same final result, and
|
||||||
|
that result has the property required by the semantics of multiplication.
|
||||||
|
|
||||||
|
Just like the example above, the lambda calculus has several different
|
||||||
|
implementations of its semantics (for example, the CESK machine or the SECD
|
||||||
|
machine). They have a more complex stack structure than a straightforward
|
||||||
|
machine implementation in, for example Python, to take. However, we can prove
|
||||||
|
that the semantics are the same.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
title: test
|
|
||||||
date: 2024-04-04T21:45:28.264
|
|
||||||
draft: true
|
|
||||||
languages: ["typst"]
|
|
||||||
tags: ["typst"]
|
|
||||||
---
|
|
||||||
|
|
||||||
```typst
|
|
||||||
#import "@preview/fletcher:0.4.3" as fletcher: diagram, node, edge
|
|
||||||
#set page(
|
|
||||||
width: auto,
|
|
||||||
height: auto,
|
|
||||||
margin: (x: 0.25em, y: 0.25em),
|
|
||||||
)
|
|
||||||
#set text(18pt)
|
|
||||||
|
|
||||||
#diagram(
|
|
||||||
node-stroke: .1em,
|
|
||||||
node-fill: gradient.radial(blue.lighten(80%), blue, center: (30%, 20%), radius: 80%),
|
|
||||||
spacing: 4em,
|
|
||||||
edge((-1,0), "r", "-|>", `open(path)`, label-pos: 0, label-side: center),
|
|
||||||
node((0,0), `reading`, radius: 2em),
|
|
||||||
edge(`read()`, "-|>"),
|
|
||||||
node((1,0), `eof`, radius: 2em),
|
|
||||||
edge(`close()`, "-|>"),
|
|
||||||
node((2,0), `closed`, radius: 2em, extrude: (-2.5, 0)),
|
|
||||||
edge((0,0), (0,0), `read()`, "--|>", bend: 130deg),
|
|
||||||
edge((0,0), (2,0), `close()`, "-|>", bend: -40deg),
|
|
||||||
)
|
|
||||||
|
|
||||||
// #diagram(cell-size: 15mm, $
|
|
||||||
// G edge(f, ->) edge("d", pi, ->>) & im(f) \
|
|
||||||
// G slash ker(f) edge("ur", tilde(f), "hook-->")
|
|
||||||
// $)
|
|
||||||
```
|
|
Loading…
Reference in a new issue