latexify
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Michael Zhang 2023-09-01 12:05:29 -05:00
parent 49cfb3ccc4
commit e94fee5345
6 changed files with 327 additions and 55 deletions

View file

@ -8,6 +8,9 @@ import emoji 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";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
@ -18,9 +21,11 @@ export default defineConfig({
remarkPlugins: [ remarkPlugins: [
remarkAdmonitions, remarkAdmonitions,
remarkReadingTime, remarkReadingTime,
remarkMath,
remarkMermaid, remarkMermaid,
emoji, emoji,
[remarkDescription, { name: "excerpt" }], [remarkDescription, { name: "excerpt" }],
], ],
rehypePlugins: [rehypeKatex],
}, },
}); });

239
package-lock.json generated
View file

@ -16,11 +16,14 @@
"astro-imagetools": "^0.9.0", "astro-imagetools": "^0.9.0",
"astro-remark-description": "^1.0.1", "astro-remark-description": "^1.0.1",
"fork-awesome": "^1.2.0", "fork-awesome": "^1.2.0",
"katex": "^0.16.8",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mdast-util-to-string": "^4.0.0", "mdast-util-to-string": "^4.0.0",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-katex": "^6.0.3",
"remark-emoji": "^4.0.0", "remark-emoji": "^4.0.0",
"remark-github-beta-blockquote-admonitions": "^2.1.0", "remark-github-beta-blockquote-admonitions": "^2.1.0",
"remark-math": "^5.1.1",
"remark-parse": "^10.0.2" "remark-parse": "^10.0.2"
}, },
"devDependencies": { "devDependencies": {
@ -1574,6 +1577,11 @@
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz",
"integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==" "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": { "node_modules/@types/lodash": {
"version": "4.14.197", "version": "4.14.197",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz",
@ -3148,6 +3156,17 @@
"once": "^1.4.0" "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": { "node_modules/es-module-lexer": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
@ -3694,6 +3713,61 @@
"node": ">=4" "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": { "node_modules/hast-util-from-parse5": {
"version": "7.1.2", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz", "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" "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": { "node_modules/hast-util-parse-selector": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", "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" "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": { "node_modules/hast-util-whitespace": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", "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", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" "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": { "node_modules/khroma": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz",
@ -4791,6 +4916,20 @@
"url": "https://opencollective.com/unified" "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": { "node_modules/mdast-util-mdx": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.1.tgz", "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.1.tgz",
@ -5205,6 +5344,29 @@
"url": "https://opencollective.com/unified" "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": { "node_modules/micromark-extension-mdx-expression": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.8.tgz", "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" "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": { "node_modules/rehype-parse": {
"version": "8.0.5", "version": "8.0.5",
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.5.tgz", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.5.tgz",
@ -7018,6 +7211,39 @@
"url": "https://opencollective.com/unified" "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": { "node_modules/remark-mdx": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.3.0.tgz", "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.3.0.tgz",
@ -8152,6 +8378,19 @@
"url": "https://opencollective.com/unified" "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": { "node_modules/unist-util-generated": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz",

View file

@ -18,11 +18,14 @@
"astro-imagetools": "^0.9.0", "astro-imagetools": "^0.9.0",
"astro-remark-description": "^1.0.1", "astro-remark-description": "^1.0.1",
"fork-awesome": "^1.2.0", "fork-awesome": "^1.2.0",
"katex": "^0.16.8",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mdast-util-to-string": "^4.0.0", "mdast-util-to-string": "^4.0.0",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-katex": "^6.0.3",
"remark-emoji": "^4.0.0", "remark-emoji": "^4.0.0",
"remark-github-beta-blockquote-admonitions": "^2.1.0", "remark-github-beta-blockquote-admonitions": "^2.1.0",
"remark-math": "^5.1.1",
"remark-parse": "^10.0.2" "remark-parse": "^10.0.2"
}, },
"devDependencies": { "devDependencies": {

View file

@ -66,21 +66,21 @@ several constructors:
[lambda calculus]: https://en.wikipedia.org/wiki/Lambda_calculus [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 meaning, but during evaluation, the evaluation _environment_ holds a mapping
from variable names to the values. If the environment says `{ x = 5 }`, then from variable names to the values. If the environment says $\{ x = 5 \}$, then
evaluating `x` would result in 5. 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 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 function with a single argument (i.e $f(x) = 2x$ is an abstraction, although
it would be written `(λx.2x)`) it would be written using the notation $\lambda x.2x$)
- **Application.** Application is sort of the opposite of abstraction, exposing - **Application.** Application is sort of the opposite of abstraction, exposing
the computation that was abstracted away. From an algebraic perspective, the computation that was abstracted away. From an algebraic perspective,
this is just function application (i.e applying `f(x) = 2x` to 3 would 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 result in $2 \times 3 = 6$. Note that only a simple substitution has been done
further evaluation is required to reduce 2\*3) and further evaluation is required to reduce $2\times 3$)
### Why? ### Why?
@ -99,20 +99,24 @@ evaluation.
In fact, the lambda calculus is [Turing-complete][tc], so any computation can 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 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 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 [church numerals]: https://en.wikipedia.org/wiki/Church_encoding
- Let `z` represent zero. - $z$ represents zero.
- Let `s` represent a "successor", or increment function. `s(z)` represents 1, - $s$ represents a "successor", or increment function. So:
`s(s(z))` represents 2, and so on. - $s(z)$ represents 1,
- $s(s(z))$ represents 2
- and so on.
In lambda calculus terms, this would look like: In lambda calculus terms, this would look like:
- 0 = `λs.(λz.z)` | number | lambda calculus expression |
- 1 = `λs.(λz.s(z))` | ------ | ---------------------------------- |
- 2 = `λs.(λz.s(s(z)))` | 0 | $\lambda s.(\lambda z.z)$ |
- 3 = `λs.(λz.s(s(s(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 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 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 [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 That's quite a mouthful. If you tried calling $Y$ on some term, you will find
evaluation will quickly expand infinitely. That makes sense given its purpose: that evaluation will quickly expand infinitely. That makes sense given its
to find a _fixed point_ of whatever function you pass in. 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 > [!NOTE]
> because f(1) = 1. The Y combinator attempts to find the fixed point by simply > As an example, the fixed-point of the function $f(x) = \sqrt{x}$ is $1$.
> applying the function multiple times. In the untyped lambda calculus, this can > That's because $f(1) = 1$, and applying $f$ to any other number sort of
> be used to implement simple (but possibly unbounded) recursion. > 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 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 program. If something is able to recurse on itself without limit, we won't be
that it'll produce the correct value? In fact, you can prove false statements able to tell what its result is, and we _definitely_ won't be able to know if
using infinite recursion as a basis. 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 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 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 ### Simply-typed lambda calculus
The [simply-typed lambda calculus] (STLC) adds types to every term. Types are The [simply-typed lambda calculus] (STLC, or the notational variant
crucial to any kind of static program analysis. Suppose I was trying to apply $\lambda^\rightarrow$) adds types to every term. Types are crucial to any kind
the term 5 to 6 (in other words, call 5 with the argument 6 as if 5 was a of static program analysis. Suppose I was trying to apply the term $5$ to $6$ (in
function). As humans we can look at that and instantly recognize that the 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 evaluation would be invalid, yet under the untyped lambda calculus, it would be
completely representable. completely representable.
[simply-typed lambda calculus]: https://en.wikipedia.org/wiki/Simply_typed_lambda_calculus [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 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 all. To say you want to apply $5$ to $6$ would not be a legal STLC term. We do
by requiring that all STLC terms are untyped lambda calculus terms accompanied this by requiring that all STLC terms are untyped lambda calculus terms
by a _type_. accompanied by a _type_.
This gives us more information about what's allowed before we run the 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 evaluation. For example, numbers may have their own type $\mathbb{N}$ (read
number"), while functions have a special "arrow" type `_ -> _`, where the "nat", for "natural number") and booleans are $\mathrm{Bool}$, while functions
underscores represent other types. A function that takes a number and returns a have a special "arrow" type $\_\rightarrow\_$, where the underscores represent
boolean (like isEven) would have the type `Nat -> Bool`, while a function that other types. A function that takes a number and returns a boolean (like isEven)
takes a boolean and returns another boolean would be `Bool -> Bool`. 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 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 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 - **Var.** Same as before, it's a variable that can be looked up in the
environment. environment.
- **Abstraction, or lambda (λ).** This is a function that carries three pieces - **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 of information:
for, (2) the _type_ of the input, and (3) the body in which the substitution
will happen. 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. - **Application.** Same as before.
It doesn't really seem like changing just one term changes the language all that 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: much. But as a result of this tiny change, _every_ term now has a type:
- `5 :: Nat` - $5 :: \mathbb{N}$
- `λ(x:Nat).2x :: Nat -> Nat` - $λ(x:\mathbb{N}).2x :: \mathbb{N} \rightarrow \mathbb{N}$
- `isEven(3) :: (Nat -> Bool) · Nat = Bool` - $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 > [!NOTE]
`x`) > 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: This also means that some values are now unrepresentable:
- `isEven(λx.2x) :: (Nat -> Bool) · (Nat -> Nat)` doesn't work because the type - $isEven(λx.2x)$ wouldn't work anymore because the type of the inner argument
of `λx.2x :: Nat -> Nat` can't be used as an input for `isEven`, which is $λx.2x$ would be $\mathbb{N} \rightarrow \mathbb{N}$ can't be used as an input
expecting a `Nat`. for $isEven$, which is expecting a $\mathbb{N}$.
We have a good foundation for writing programs now, but this by itself can't 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 qualify as a system for computation. We need an abstract machine of sorts that

View file

@ -2,6 +2,7 @@
import Footer from "../components/Footer.astro"; import Footer from "../components/Footer.astro";
import LeftNav from "../components/LeftNav.astro"; import LeftNav from "../components/LeftNav.astro";
import "../styles/global.scss"; import "../styles/global.scss";
import "katex/dist/katex.min.css";
--- ---
<!doctype html> <!doctype html>

View file

@ -160,9 +160,12 @@
table { table {
border-collapse: collapse; border-collapse: collapse;
border: 1px solid var(--hr-color);
border-radius: 4px;
thead { thead {
background-color: black; background-color: var(--hr-color);
// color: var(--background-color);
} }
td, td,
@ -239,10 +242,9 @@ hr.endline {
.admonition-title { .admonition-title {
color: var(--color); color: var(--color);
margin-bottom: 6px;
} }
p { p {
margin: 0; margin: 8px auto;
} }
} }