This commit is contained in:
parent
49cfb3ccc4
commit
e94fee5345
6 changed files with 327 additions and 55 deletions
|
@ -8,6 +8,9 @@ import emoji from "remark-emoji";
|
|||
import remarkMermaid from "astro-diagram/remark-mermaid";
|
||||
import remarkDescription from "astro-remark-description";
|
||||
import remarkAdmonitions from "./plugin/remark-admonitions";
|
||||
import remarkMath from "remark-math";
|
||||
|
||||
import rehypeKatex from "rehype-katex";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
|
@ -18,9 +21,11 @@ export default defineConfig({
|
|||
remarkPlugins: [
|
||||
remarkAdmonitions,
|
||||
remarkReadingTime,
|
||||
remarkMath,
|
||||
remarkMermaid,
|
||||
emoji,
|
||||
[remarkDescription, { name: "excerpt" }],
|
||||
],
|
||||
rehypePlugins: [rehypeKatex],
|
||||
},
|
||||
});
|
||||
|
|
239
package-lock.json
generated
239
package-lock.json
generated
|
@ -16,11 +16,14 @@
|
|||
"astro-imagetools": "^0.9.0",
|
||||
"astro-remark-description": "^1.0.1",
|
||||
"fork-awesome": "^1.2.0",
|
||||
"katex": "^0.16.8",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"reading-time": "^1.5.0",
|
||||
"rehype-katex": "^6.0.3",
|
||||
"remark-emoji": "^4.0.0",
|
||||
"remark-github-beta-blockquote-admonitions": "^2.1.0",
|
||||
"remark-math": "^5.1.1",
|
||||
"remark-parse": "^10.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1574,6 +1577,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz",
|
||||
"integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA=="
|
||||
},
|
||||
"node_modules/@types/katex": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.14.0.tgz",
|
||||
"integrity": "sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA=="
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.197",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz",
|
||||
|
@ -3148,6 +3156,17 @@
|
|||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
|
||||
|
@ -3694,6 +3713,61 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-dom": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-4.2.0.tgz",
|
||||
"integrity": "sha512-t1RJW/OpJbCAJQeKi3Qrj1cAOLA0+av/iPFori112+0X7R3wng+jxLA+kXec8K4szqPRGI8vPxbbpEYvvpwaeQ==",
|
||||
"dependencies": {
|
||||
"hastscript": "^7.0.0",
|
||||
"web-namespaces": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-1.0.2.tgz",
|
||||
"integrity": "sha512-LhrTA2gfCbLOGJq2u/asp4kwuG0y6NhWTXiPKP+n0qNukKy7hc10whqqCFfyvIA1Q5U5d0sp9HhNim9gglEH4A==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"hast-util-from-parse5": "^7.0.0",
|
||||
"parse5": "^7.0.0",
|
||||
"vfile": "^5.0.0",
|
||||
"vfile-message": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html-isomorphic": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-1.0.0.tgz",
|
||||
"integrity": "sha512-Yu480AKeOEN/+l5LA674a+7BmIvtDj24GvOt7MtQWuhzUwlaaRWdEPXAh3Qm5vhuthpAipFb2vTetKXWOjmTvw==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"hast-util-from-dom": "^4.0.0",
|
||||
"hast-util-from-html": "^1.0.0",
|
||||
"unist-util-remove-position": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html/node_modules/parse5": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
||||
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
||||
"dependencies": {
|
||||
"entities": "^4.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-parse5": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz",
|
||||
|
@ -3712,6 +3786,19 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-is-element": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz",
|
||||
"integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"@types/unist": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-parse-selector": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz",
|
||||
|
@ -3825,6 +3912,21 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-text": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-3.1.2.tgz",
|
||||
"integrity": "sha512-tcllLfp23dJJ+ju5wCCZHVpzsQQ43+moJbqVX3jNWPB7z/KFC4FyZD6R7y94cHL6MQ33YtMZL8Z0aIXXI4XFTw==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"@types/unist": "^2.0.0",
|
||||
"hast-util-is-element": "^2.0.0",
|
||||
"unist-util-find-after": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-whitespace": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz",
|
||||
|
@ -4382,6 +4484,29 @@
|
|||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
|
||||
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
|
||||
},
|
||||
"node_modules/katex": {
|
||||
"version": "0.16.8",
|
||||
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.8.tgz",
|
||||
"integrity": "sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==",
|
||||
"funding": [
|
||||
"https://opencollective.com/katex",
|
||||
"https://github.com/sponsors/katex"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "^8.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"katex": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/katex/node_modules/commander": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/khroma": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz",
|
||||
|
@ -4791,6 +4916,20 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-math": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-2.0.2.tgz",
|
||||
"integrity": "sha512-8gmkKVp9v6+Tgjtq6SYx9kGPpTf6FVYRa53/DLh479aldR9AyP48qeVOgNZ5X7QUK7nOy4yw7vg6mbiGcs9jWQ==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"longest-streak": "^3.0.0",
|
||||
"mdast-util-to-markdown": "^1.3.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.1.tgz",
|
||||
|
@ -5205,6 +5344,29 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-math": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-2.1.2.tgz",
|
||||
"integrity": "sha512-es0CcOV89VNS9wFmyn+wyFTKweXGW4CEvdaAca6SWRWPyYCbBisnjaHLjWO4Nszuiud84jCpkHsqAJoa768Pvg==",
|
||||
"dependencies": {
|
||||
"@types/katex": "^0.16.0",
|
||||
"katex": "^0.16.0",
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0",
|
||||
"uvu": "^0.5.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-math/node_modules/@types/katex": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.2.tgz",
|
||||
"integrity": "sha512-dHsSjSlU/EWEEbeNADr3FtZZOAXPkFPUO457QCnoNqcZQXNqNEu/svQd0Nritvd3wNff4vvC/f4e6xgX3Llt8A=="
|
||||
},
|
||||
"node_modules/micromark-extension-mdx-expression": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.8.tgz",
|
||||
|
@ -6738,6 +6900,37 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-katex": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-6.0.3.tgz",
|
||||
"integrity": "sha512-ByZlRwRUcWegNbF70CVRm2h/7xy7jQ3R9LaY4VVSvjnoVWwWVhNL60DiZsBpC5tSzYQOCvDbzncIpIjPZWodZA==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"@types/katex": "^0.14.0",
|
||||
"hast-util-from-html-isomorphic": "^1.0.0",
|
||||
"hast-util-to-text": "^3.1.0",
|
||||
"katex": "^0.16.0",
|
||||
"unist-util-visit": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-katex/node_modules/unist-util-visit": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz",
|
||||
"integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"unist-util-is": "^5.0.0",
|
||||
"unist-util-visit-parents": "^5.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-parse": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.5.tgz",
|
||||
|
@ -7018,6 +7211,39 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-math": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/remark-math/-/remark-math-5.1.1.tgz",
|
||||
"integrity": "sha512-cE5T2R/xLVtfFI4cCePtiRn+e6jKMtFDR3P8V3qpv8wpKjwvHoBA4eJzvX+nVrnlNy0911bdGmuspCSwetfYHw==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"mdast-util-math": "^2.0.0",
|
||||
"micromark-extension-math": "^2.0.0",
|
||||
"unified": "^10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-math/node_modules/unified": {
|
||||
"version": "10.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz",
|
||||
"integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"bail": "^2.0.0",
|
||||
"extend": "^3.0.0",
|
||||
"is-buffer": "^2.0.0",
|
||||
"is-plain-obj": "^4.0.0",
|
||||
"trough": "^2.0.0",
|
||||
"vfile": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-mdx": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.3.0.tgz",
|
||||
|
@ -8152,6 +8378,19 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-find-after": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-4.0.1.tgz",
|
||||
"integrity": "sha512-QO/PuPMm2ERxC6vFXEPtmAutOopy5PknD+Oq64gGwxKtk4xwo9Z97t9Av1obPmGU0IyTa6EKYUfTrK2QJS3Ozw==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"unist-util-is": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-generated": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz",
|
||||
|
|
|
@ -18,11 +18,14 @@
|
|||
"astro-imagetools": "^0.9.0",
|
||||
"astro-remark-description": "^1.0.1",
|
||||
"fork-awesome": "^1.2.0",
|
||||
"katex": "^0.16.8",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"reading-time": "^1.5.0",
|
||||
"rehype-katex": "^6.0.3",
|
||||
"remark-emoji": "^4.0.0",
|
||||
"remark-github-beta-blockquote-admonitions": "^2.1.0",
|
||||
"remark-math": "^5.1.1",
|
||||
"remark-parse": "^10.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -66,21 +66,21 @@ several constructors:
|
|||
|
||||
[lambda calculus]: https://en.wikipedia.org/wiki/Lambda_calculus
|
||||
|
||||
- **Var.** This is just a variable, like `x` or `y`. By itself it holds no
|
||||
- **Var.** This is just a variable, like $x$ or $y$. By itself it holds no
|
||||
meaning, but during evaluation, the evaluation _environment_ holds a mapping
|
||||
from variable names to the values. If the environment says `{ x = 5 }`, then
|
||||
evaluating `x` would result in 5.
|
||||
from variable names to the values. If the environment says $\{ x = 5 \}$, then
|
||||
evaluating $x$ would result in $5$.
|
||||
|
||||
- **Abstraction, or lambda (λ).** An _abstraction_ is a term that describes some
|
||||
- **Abstraction, or lambda ($\lambda$).** An _abstraction_ is a term that describes some
|
||||
other computation. From an algebraic perspective, it can be thought of as a
|
||||
function with a single argument (i.e f(x) = 2x is an abstraction, although
|
||||
it would be written `(λx.2x)`)
|
||||
function with a single argument (i.e $f(x) = 2x$ is an abstraction, although
|
||||
it would be written using the notation $\lambda x.2x$)
|
||||
|
||||
- **Application.** Application is sort of the opposite of abstraction, exposing
|
||||
the computation that was abstracted away. From an algebraic perspective,
|
||||
this is just function application (i.e applying `f(x) = 2x` to 3 would
|
||||
result in 2\*3. Note that only a simple substitution has been done and
|
||||
further evaluation is required to reduce 2\*3)
|
||||
this is just function application (i.e applying $f(x) = 2x$ to $3$ would
|
||||
result in $2 \times 3 = 6$. Note that only a simple substitution has been done
|
||||
and further evaluation is required to reduce $2\times 3$)
|
||||
|
||||
### Why?
|
||||
|
||||
|
@ -99,20 +99,24 @@ evaluation.
|
|||
In fact, the lambda calculus is [Turing-complete][tc], so any computation can
|
||||
technically be reduced to those 3 constructs. I used numbers liberally in the
|
||||
examples above, but in a lambda calculus without numbers, you could define
|
||||
integers using a recursive strategy called [Church numerals]. It looks like this:
|
||||
integers using a recursive strategy called [Church numerals]. It works like this:
|
||||
|
||||
[church numerals]: https://en.wikipedia.org/wiki/Church_encoding
|
||||
|
||||
- Let `z` represent zero.
|
||||
- Let `s` represent a "successor", or increment function. `s(z)` represents 1,
|
||||
`s(s(z))` represents 2, and so on.
|
||||
- $z$ represents zero.
|
||||
- $s$ represents a "successor", or increment function. So:
|
||||
- $s(z)$ represents 1,
|
||||
- $s(s(z))$ represents 2
|
||||
- and so on.
|
||||
|
||||
In lambda calculus terms, this would look like:
|
||||
|
||||
- 0 = `λs.(λz.z)`
|
||||
- 1 = `λs.(λz.s(z))`
|
||||
- 2 = `λs.(λz.s(s(z)))`
|
||||
- 3 = `λs.(λz.s(s(s(z))))`
|
||||
| number | lambda calculus expression |
|
||||
| ------ | ---------------------------------- |
|
||||
| 0 | $\lambda s.(\lambda z.z)$ |
|
||||
| 1 | $\lambda s.(\lambda z.s(z))$ |
|
||||
| 2 | $\lambda s.(\lambda z.s(s(z)))$ |
|
||||
| 3 | $\lambda s.(\lambda z.s(s(s(z))))$ |
|
||||
|
||||
In practice, many lambda calculus incorporate higher level constructors such as
|
||||
numbers or lists to make it so we can avoid having to represent them using only
|
||||
|
@ -129,21 +133,31 @@ a fixed-point combinator:
|
|||
|
||||
[tc]: https://en.wikipedia.org/wiki/Turing_completeness
|
||||
|
||||
Y = λf.(λx.f(x(x)))(λx.f(x(x)))
|
||||
$$
|
||||
Y = \lambda f.(\lambda x.f(x(x)))(\lambda x.f(x(x)))
|
||||
$$
|
||||
|
||||
That's quite a mouthful. If you tried calling Y on some term, you will find that
|
||||
evaluation will quickly expand infinitely. That makes sense given its purpose:
|
||||
to find a _fixed point_ of whatever function you pass in.
|
||||
That's quite a mouthful. If you tried calling $Y$ on some term, you will find
|
||||
that evaluation will quickly expand infinitely. That makes sense given its
|
||||
purpose: to find a _fixed point_ of whatever function you pass in.
|
||||
|
||||
> As an example, the fixed-point of the function f(x) = sqrt(x) is 1. That's
|
||||
> because f(1) = 1. The Y combinator attempts to find the fixed point by simply
|
||||
> applying the function multiple times. In the untyped lambda calculus, this can
|
||||
> be used to implement simple (but possibly unbounded) recursion.
|
||||
> [!NOTE]
|
||||
> As an example, the fixed-point of the function $f(x) = \sqrt{x}$ is $1$.
|
||||
> That's because $f(1) = 1$, and applying $f$ to any other number sort of
|
||||
> converges in on this value. If you took any number and applied $f$ infinitely
|
||||
> many times on it, you would get $1$.
|
||||
>
|
||||
> In this sense, the Y combinator can be seen as a sort of brute-force approach
|
||||
> of finding this fixed point by simply applying the function over and over until
|
||||
> the result stops changing. In the untyped lambda calculus, this can be used to
|
||||
> implement simple (but possibly unbounded) recursion.
|
||||
|
||||
This actually proves disastrous for trying to reason about the logic of a
|
||||
program. If we don't even know for sure if something will halt, how can we know
|
||||
that it'll produce the correct value? In fact, you can prove false statements
|
||||
using infinite recursion as a basis.
|
||||
program. If something is able to recurse on itself without limit, we won't be
|
||||
able to tell what its result is, and we _definitely_ won't be able to know if
|
||||
the result is correct. This is why we typically ban unbounded recursion in
|
||||
proof systems. In fact, you can give proofs for false statements using infinite
|
||||
recursion.
|
||||
|
||||
This is why we actually prefer _not_ to work with Turing-complete languages when
|
||||
doing logical reasoning on program evaluation. Instead, we always want to add
|
||||
|
@ -152,26 +166,29 @@ information about our program's behavior.
|
|||
|
||||
### Simply-typed lambda calculus
|
||||
|
||||
The [simply-typed lambda calculus] (STLC) adds types to every term. Types are
|
||||
crucial to any kind of static program analysis. Suppose I was trying to apply
|
||||
the term 5 to 6 (in other words, call 5 with the argument 6 as if 5 was a
|
||||
function). As humans we can look at that and instantly recognize that the
|
||||
The [simply-typed lambda calculus] (STLC, or the notational variant
|
||||
$\lambda^\rightarrow$) adds types to every term. Types are crucial to any kind
|
||||
of static program analysis. Suppose I was trying to apply the term $5$ to $6$ (in
|
||||
other words, call $5$ with the argument $6$ as if $5$ was a function, like
|
||||
$5(6)$). As humans we can look at that and instantly recognize that the
|
||||
evaluation would be invalid, yet under the untyped lambda calculus, it would be
|
||||
completely representable.
|
||||
|
||||
[simply-typed lambda calculus]: https://en.wikipedia.org/wiki/Simply_typed_lambda_calculus
|
||||
|
||||
To solve this in STLC, we would make this term completely unrepresentable at
|
||||
all. To say you want to apply 5 to 6 would not be a legal STLC term. We do this
|
||||
by requiring that all STLC terms are untyped lambda calculus terms accompanied
|
||||
by a _type_.
|
||||
all. To say you want to apply $5$ to $6$ would not be a legal STLC term. We do
|
||||
this by requiring that all STLC terms are untyped lambda calculus terms
|
||||
accompanied by a _type_.
|
||||
|
||||
This gives us more information about what's allowed before we run the
|
||||
evaluation. For example, numbers may have their own type `Nat` (for "natural
|
||||
number"), while functions have a special "arrow" type `_ -> _`, where the
|
||||
underscores represent other types. A function that takes a number and returns a
|
||||
boolean (like isEven) would have the type `Nat -> Bool`, while a function that
|
||||
takes a boolean and returns another boolean would be `Bool -> Bool`.
|
||||
evaluation. For example, numbers may have their own type $\mathbb{N}$ (read
|
||||
"nat", for "natural number") and booleans are $\mathrm{Bool}$, while functions
|
||||
have a special "arrow" type $\_\rightarrow\_$, where the underscores represent
|
||||
other types. A function that takes a number and returns a boolean (like isEven)
|
||||
would have the type $\mathbb{N} \rightarrow \mathrm{Bool}$, while a function
|
||||
that takes a boolean and returns another boolean would be $\mathrm{Bool}
|
||||
\rightarrow \mathrm{Bool}$.
|
||||
|
||||
With this, we have a framework for rejecting terms that would otherwise be legal
|
||||
in untyped lambda calculus, but would break when we tried to evaluate them. A
|
||||
|
@ -187,28 +204,33 @@ A semi-formal definition for STLC terms would look something like this:
|
|||
- **Var.** Same as before, it's a variable that can be looked up in the
|
||||
environment.
|
||||
|
||||
- **Abstraction, or lambda (λ).** This is a function that carries three pieces
|
||||
of information: (1) the name of the variable that its input will be substituted
|
||||
for, (2) the _type_ of the input, and (3) the body in which the substitution
|
||||
will happen.
|
||||
- **Abstraction, or lambda ($\lambda$).** This is a function that carries three pieces
|
||||
of information:
|
||||
|
||||
1. the name of the variable that its input will be substituted for
|
||||
2. the _type_ of the input, and
|
||||
3. the body in which the substitution will happen.
|
||||
|
||||
- **Application.** Same as before.
|
||||
|
||||
It doesn't really seem like changing just one term changes the language all that
|
||||
much. But as a result of this tiny change, _every_ term now has a type:
|
||||
|
||||
- `5 :: Nat`
|
||||
- `λ(x:Nat).2x :: Nat -> Nat`
|
||||
- `isEven(3) :: (Nat -> Bool) · Nat = Bool`
|
||||
- $5 :: \mathbb{N}$
|
||||
- $λ(x:\mathbb{N}).2x :: \mathbb{N} \rightarrow \mathbb{N}$
|
||||
- $isEven(3) :: (\mathbb{N} \rightarrow \mathrm{Bool}) · \mathbb{N} = \mathrm{Bool}$
|
||||
|
||||
Notation: (`x :: T` means `x` has type `T`, and `f · x` means `f` applied to
|
||||
`x`)
|
||||
> [!NOTE]
|
||||
> Some notation:
|
||||
>
|
||||
> - $x :: T$ means $x$ has type $T$, and
|
||||
> - $f · x$ means $f$ applied to $x$
|
||||
|
||||
This also means that some values are now unrepresentable:
|
||||
|
||||
- `isEven(λx.2x) :: (Nat -> Bool) · (Nat -> Nat)` doesn't work because the type
|
||||
of `λx.2x :: Nat -> Nat` can't be used as an input for `isEven`, which is
|
||||
expecting a `Nat`.
|
||||
- $isEven(λx.2x)$ wouldn't work anymore because the type of the inner argument
|
||||
$λx.2x$ would be $\mathbb{N} \rightarrow \mathbb{N}$ can't be used as an input
|
||||
for $isEven$, which is expecting a $\mathbb{N}$.
|
||||
|
||||
We have a good foundation for writing programs now, but this by itself can't
|
||||
qualify as a system for computation. We need an abstract machine of sorts that
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import Footer from "../components/Footer.astro";
|
||||
import LeftNav from "../components/LeftNav.astro";
|
||||
import "../styles/global.scss";
|
||||
import "katex/dist/katex.min.css";
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
|
|
|
@ -160,9 +160,12 @@
|
|||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid var(--hr-color);
|
||||
border-radius: 4px;
|
||||
|
||||
thead {
|
||||
background-color: black;
|
||||
background-color: var(--hr-color);
|
||||
// color: var(--background-color);
|
||||
}
|
||||
|
||||
td,
|
||||
|
@ -239,10 +242,9 @@ hr.endline {
|
|||
|
||||
.admonition-title {
|
||||
color: var(--color);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
margin: 8px auto;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue