summaryrefslogtreecommitdiff
path: root/src/scenes
diff options
context:
space:
mode:
Diffstat (limited to 'src/scenes')
-rw-r--r--src/scenes/boolean_algebra_lambda.meta5
-rw-r--r--src/scenes/boolean_algebra_lambda.tsx49
-rw-r--r--src/scenes/boolean_encoding.meta5
-rw-r--r--src/scenes/boolean_encoding.tsx42
-rw-r--r--src/scenes/church_encoding.meta5
-rw-r--r--src/scenes/church_encoding.tsx41
-rw-r--r--src/scenes/currying.meta5
-rw-r--r--src/scenes/currying.tsx114
-rw-r--r--src/scenes/currying_detail.meta5
-rw-r--r--src/scenes/currying_detail.tsx155
-rw-r--r--src/scenes/dna.meta5
-rw-r--r--src/scenes/dna.tsx22
-rw-r--r--src/scenes/function_dna.meta5
-rw-r--r--src/scenes/function_dna.tsx91
-rw-r--r--src/scenes/further.meta5
-rw-r--r--src/scenes/further.tsx43
-rw-r--r--src/scenes/generalized.tsx6
-rw-r--r--src/scenes/impostor.meta5
-rw-r--r--src/scenes/impostor.tsx134
-rw-r--r--src/scenes/index.ts58
-rw-r--r--src/scenes/lambda_recursion.meta5
-rw-r--r--src/scenes/lambda_recursion.tsx45
-rw-r--r--src/scenes/lambda_reduction_example.meta5
-rw-r--r--src/scenes/lambda_reduction_example.tsx47
-rw-r--r--src/scenes/me.tsx8
-rw-r--r--src/scenes/parttwo.meta5
-rw-r--r--src/scenes/parttwo.tsx16
-rw-r--r--src/scenes/pros_cons.meta5
-rw-r--r--src/scenes/pros_cons.tsx61
-rw-r--r--src/scenes/questions.meta5
-rw-r--r--src/scenes/questions.tsx16
-rw-r--r--src/scenes/recursion.meta5
-rw-r--r--src/scenes/recursion.tsx36
-rw-r--r--src/scenes/reductions.meta5
-rw-r--r--src/scenes/reductions.tsx40
-rw-r--r--src/scenes/substitution.meta5
-rw-r--r--src/scenes/substitution.tsx45
-rw-r--r--src/scenes/the_lambda_calculus.meta5
-rw-r--r--src/scenes/the_lambda_calculus.tsx40
39 files changed, 1181 insertions, 18 deletions
diff --git a/src/scenes/boolean_algebra_lambda.meta b/src/scenes/boolean_algebra_lambda.meta
new file mode 100644
index 0000000..385a68c
--- /dev/null
+++ b/src/scenes/boolean_algebra_lambda.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2667185663
+} \ No newline at end of file
diff --git a/src/scenes/boolean_algebra_lambda.tsx b/src/scenes/boolean_algebra_lambda.tsx
new file mode 100644
index 0000000..2639461
--- /dev/null
+++ b/src/scenes/boolean_algebra_lambda.tsx
@@ -0,0 +1,49 @@
+import { Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { LambdaReducer } from "../components/lambda_reducer";
+import { baseDefinitions } from "../utils/lambdas";
+
+export default makeScene2D(function* (view) {
+ const lambdaReducer = createRef<LambdaReducer>();
+ const layout = createRef<Layout>();
+
+ view.add(
+ <Layout
+ layout
+ ref={layout}
+ direction="column"
+ alignItems="center"
+ gap={50}
+ ></Layout>
+ );
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("Boolean Reductions");
+
+ for (const term of [
+ "((false one) zero)",
+ "((true one) zero)",
+ "(((if true) one) zero)",
+ ]) {
+ yield* layout().opacity(0, 0.5);
+ layout().add(
+ <LambdaReducer
+ ref={lambdaReducer}
+ lambdaTerm={term}
+ definitions={baseDefinitions}
+ ></LambdaReducer>
+ );
+ yield* layout().opacity(1, 0.5);
+
+ yield* beginSlide("Next Reduction " + term);
+ for (let i = 0; !lambdaReducer().isDone(); i++) {
+ yield* lambdaReducer().step(0.5);
+ yield* beginSlide(term + " Next Step " + i);
+ }
+ layout().removeChildren();
+ }
+});
diff --git a/src/scenes/boolean_encoding.meta b/src/scenes/boolean_encoding.meta
new file mode 100644
index 0000000..8f4d744
--- /dev/null
+++ b/src/scenes/boolean_encoding.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2394701117
+} \ No newline at end of file
diff --git a/src/scenes/boolean_encoding.tsx b/src/scenes/boolean_encoding.tsx
new file mode 100644
index 0000000..60a0ea9
--- /dev/null
+++ b/src/scenes/boolean_encoding.tsx
@@ -0,0 +1,42 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const boolE = [
+ "true = λ t . λ f . t",
+ "false = λ t . λ f . f",
+ "if = λ b . λ x . λ y . b x y",
+ "not = λ b . b false true",
+ "and = λ b . λ c . b c false",
+];
+
+export default makeScene2D(function* (view) {
+ const numerals = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ Boolean Encoding
+ </Txt>
+ <Txt
+ ref={numerals}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("The Lambda Calculus - Boolean Encoding");
+
+ for (const bool of boolE) {
+ yield* numerals().text(numerals().text() + "\n\n" + bool, 1);
+ yield* beginSlide("boolean - " + bool);
+ }
+});
diff --git a/src/scenes/church_encoding.meta b/src/scenes/church_encoding.meta
new file mode 100644
index 0000000..638e825
--- /dev/null
+++ b/src/scenes/church_encoding.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 533121975
+} \ No newline at end of file
diff --git a/src/scenes/church_encoding.tsx b/src/scenes/church_encoding.tsx
new file mode 100644
index 0000000..70bafe4
--- /dev/null
+++ b/src/scenes/church_encoding.tsx
@@ -0,0 +1,41 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const churchNumerals = [
+ "0 = λ f . λ x . x (no application of f)",
+ "1 = λ f . λ x . f x (one application of f)",
+ "2 = λ f . λ x . f (f x) (two applications of f)",
+ "succ = λ n . λ f . λ x . f ((n f) x)",
+];
+
+export default makeScene2D(function* (view) {
+ const numerals = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ Church Encoding
+ </Txt>
+ <Txt
+ ref={numerals}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("The Lambda Calculus - Church Encoding");
+
+ for (const numeral of churchNumerals) {
+ yield* numerals().text(numerals().text() + "\n\n" + numeral, 1);
+ yield* beginSlide("substitution - " + numeral);
+ }
+});
diff --git a/src/scenes/currying.meta b/src/scenes/currying.meta
new file mode 100644
index 0000000..1dd71f1
--- /dev/null
+++ b/src/scenes/currying.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2262306570
+} \ No newline at end of file
diff --git a/src/scenes/currying.tsx b/src/scenes/currying.tsx
new file mode 100644
index 0000000..01ce24a
--- /dev/null
+++ b/src/scenes/currying.tsx
@@ -0,0 +1,114 @@
+import { Video, Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ all,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { PEOPLE, Person, PersonI } from "../components/person";
+import { birthdayCardFn, valentineCardFn } from "./generalized";
+import { CardI } from "./birthday_letters";
+import { FunctionBox } from "../components/function_box";
+import curry from "../../public/img/curry.mp4";
+
+export const cardGeneratorsFor = (
+ person: PersonI,
+): ((type: string) => () => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person);
+ const valentineCardGenerator = () => valentineCardFn(person);
+
+ const messageType = (type: string) => {
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+ throw new Error(type + " not implemented");
+ };
+
+ return messageType;
+};
+
+export const cardGeneratorsForSource = `const cardGeneratorsFor = (person: PersonI): ((type: string) => () => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person);
+ const valentineCardGenerator = () => valentineCardFn(person);
+
+ const generatorForType = (type: string) => {
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+
+ throw new Error(type + " not implemented");
+ };
+
+ return generatorForType;
+};`;
+
+export default makeScene2D(function* (view) {
+ const box = createRef<FunctionBox>();
+ const vid = createRef<Video>();
+
+ view.add(
+ <Layout>
+ <FunctionBox
+ ref={box}
+ fn={cardGeneratorsFor}
+ source={cardGeneratorsForSource}
+ outputFontSize={20}
+ />
+ <Video ref={vid} src={curry} width={0} />
+ </Layout>,
+ );
+
+ yield* all(
+ box().reset(0.1),
+ box().showCode(0.5),
+ slideTransition(Direction.Left, 0.5),
+ );
+
+ yield* beginSlide("show code");
+
+ const [alan] = PEOPLE;
+ yield* box().setInputs([{ val: alan, node: <Person person={alan} /> }], 0.5);
+
+ yield* beginSlide("show inputs");
+
+ yield* box().hideCode(0.5);
+ yield* box().propogateInput(0.5);
+ yield* box().propogateOutput(0.5);
+
+ yield* beginSlide("create child function");
+
+ const child = box().getChild();
+ yield* child().showCode(0.5);
+
+ yield* beginSlide("show child function");
+
+ yield* child().hideCode(0.5);
+ yield* child().setInputs([{ val: "valentine" }], 0.5);
+ yield* child().propogateInput(0.5);
+ yield* child().propogateOutput(0.5);
+
+ const curriedChild = child().getChild();
+ yield* curriedChild().showCode(0.5);
+
+ yield* beginSlide("propogate child function");
+
+ yield* curriedChild().hideCode(0.5);
+ yield* curriedChild().setInputs([{ val: "" }], 0.5);
+ yield* curriedChild().propogateInput(0.5);
+ yield* curriedChild().propogateOutput(0.5);
+
+ yield* beginSlide("propogate curry");
+
+ yield vid().play();
+ yield vid().loop(true);
+ yield* vid().width(400, 2);
+
+ yield* beginSlide("do i smell curry");
+});
diff --git a/src/scenes/currying_detail.meta b/src/scenes/currying_detail.meta
new file mode 100644
index 0000000..71a034a
--- /dev/null
+++ b/src/scenes/currying_detail.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2012730104
+} \ No newline at end of file
diff --git a/src/scenes/currying_detail.tsx b/src/scenes/currying_detail.tsx
new file mode 100644
index 0000000..fd7c3d3
--- /dev/null
+++ b/src/scenes/currying_detail.tsx
@@ -0,0 +1,155 @@
+import { Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import {
+ CodeBlock,
+ edit,
+ insert,
+ range,
+} from "@motion-canvas/2d/lib/components/CodeBlock";
+import { cardGeneratorForSource } from "./function_dna";
+import { cardGeneratorsForSource } from "./currying";
+
+export default makeScene2D(function* (view) {
+ const curried = createRef<CodeBlock>();
+
+ view.add(
+ <Layout direction="row" gap={100} layout>
+ <CodeBlock
+ fontSize={25}
+ language="typescript"
+ ref={curried}
+ code={cardGeneratorForSource}
+ />
+ </Layout>,
+ );
+
+ yield* slideTransition(Direction.Left);
+
+ yield* beginSlide("show function");
+
+ yield* curried().edit(
+ 1,
+ )`const cardGeneratorFor = (person: PersonI, type: string): (() => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person); // closure
+ const valentineCardGenerator = () => valentineCardFn(person); // closure${insert(
+ "\n",
+ )}
+ ${insert(`const generatorForType = (type: string) => {`)}
+ ${insert(" ")}switch (type) {
+ ${insert(" ")} case "valentine":
+ ${insert(" ")} return valentineCardGenerator;
+ ${insert(" ")} case "birthday":
+ ${insert(" ")} return birthdayCardGenerator;
+ ${insert(" ")}}
+
+ ${insert(" ")}throw new Error(type + " not implemented");
+ ${insert("};\n")}}`;
+
+ yield* beginSlide("first currying step");
+
+ yield* curried().edit(
+ 1,
+ )`const cardGeneratorFor = (person: PersonI, type: string): (() => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person); // closure
+ const valentineCardGenerator = () => valentineCardFn(person); // closure
+
+ const generatorForType = (type: string) => {
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+
+ throw new Error(type + " not implemented");
+ };${insert("\n\n return generatorForType;")}
+}`;
+ yield* beginSlide("second currying step");
+
+ yield* curried().edit(1)`const ${edit(
+ "cardGeneratorFor",
+ "cardGeneratorsFor",
+ )} = ${edit(
+ "(person: PersonI, type: string)",
+ "(person: PersonI)",
+ )}: (() => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person); // closure
+ const valentineCardGenerator = () => valentineCardFn(person); // closure
+
+ const generatorForType = (type: string) => {
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+
+ throw new Error(type + " not implemented");
+ };
+
+ return generatorForType;
+}`;
+ yield* beginSlide("third currying step");
+
+ yield* curried().edit(1)`const cardGeneratorsFor = (person: PersonI): ${edit(
+ "(() => CardI)",
+ "((type: string) => () => CardI)",
+ )} => {
+ const birthdayCardGenerator = () => birthdayCardFn(person); // closure
+ const valentineCardGenerator = () => valentineCardFn(person); // closure
+
+ const generatorForType = (type: string) => {
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+
+ throw new Error(type + " not implemented");
+ };
+
+ return generatorForType;
+}`;
+ yield* beginSlide("fourth currying step");
+
+ yield* curried().edit(1)`${edit(
+ cardGeneratorsForSource,
+ `const alanCardGenerator = (type: string): (() => CardI) => {
+ const alan: PersonI = {
+ name: "Alan Turing",
+ birthday: new Date("06/23/1912"),
+ color: theme.green.hex,
+ };
+
+ return cardGeneratorFor(alan, type);
+};`,
+ )}`;
+ yield* beginSlide("partial application");
+
+ yield* curried().selection(
+ [...range(7, 9, 7, 38), ...range(0, 26, 0, 40)],
+ 1,
+ );
+
+ yield* beginSlide("highlight");
+
+ yield* curried().edit(
+ 1,
+ )`const alanCardGenerator = (type: string): (() => CardI) => {
+ const alan: PersonI = {
+ name: "Alan Turing",
+ birthday: new Date("06/23/1912"),
+ color: theme.green.hex,
+ };
+
+ return cardGeneratorFor(alan, type);
+};${insert(`
+(alanCardGenerator("valentine")()).message === (cardGeneratorsFor(alan)("valentine")()).message;`)}`;
+ yield* beginSlide("show application of pa");
+});
diff --git a/src/scenes/dna.meta b/src/scenes/dna.meta
new file mode 100644
index 0000000..c1ba9fb
--- /dev/null
+++ b/src/scenes/dna.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 659686876
+} \ No newline at end of file
diff --git a/src/scenes/dna.tsx b/src/scenes/dna.tsx
new file mode 100644
index 0000000..9cb77bd
--- /dev/null
+++ b/src/scenes/dna.tsx
@@ -0,0 +1,22 @@
+import { Video, Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import mitosis from "../../public/img/cell_division.mp4";
+
+export default makeScene2D(function* (view) {
+ const layout = createRef<Layout>();
+ const vid = createRef<Video>();
+
+ view.add(
+ <Video playbackRate={4} width={900} ref={vid} src={mitosis} x={0} />,
+ );
+
+ yield* slideTransition(Direction.Left);
+ yield vid().play();
+ yield vid().loop(true);
+ yield* beginSlide("show mitosis");
+});
diff --git a/src/scenes/function_dna.meta b/src/scenes/function_dna.meta
new file mode 100644
index 0000000..2648f3d
--- /dev/null
+++ b/src/scenes/function_dna.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 4141071538
+} \ No newline at end of file
diff --git a/src/scenes/function_dna.tsx b/src/scenes/function_dna.tsx
new file mode 100644
index 0000000..64098d3
--- /dev/null
+++ b/src/scenes/function_dna.tsx
@@ -0,0 +1,91 @@
+import { makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ all,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { PEOPLE, Person, PersonI } from "../components/person";
+import { birthdayCardFn, valentineCardFn } from "./generalized";
+import { CardI } from "./birthday_letters";
+import { FunctionBox } from "../components/function_box";
+
+export const cardGeneratorFor = (
+ person: PersonI,
+ type: string,
+): (() => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person);
+ const valentineCardGenerator = () => valentineCardFn(person);
+
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+
+ throw new Error(type + " not implemented");
+};
+
+export const cardGeneratorForSource = `const cardGeneratorFor = (person: PersonI, type: string): (() => CardI) => {
+ const birthdayCardGenerator = () => birthdayCardFn(person); // closure
+ const valentineCardGenerator = () => valentineCardFn(person); // closure
+
+ switch (type) {
+ case "valentine":
+ return valentineCardGenerator;
+ case "birthday":
+ return birthdayCardGenerator;
+ }
+
+ throw new Error(type + " not implemented");
+}`;
+
+export default makeScene2D(function* (view) {
+ const box = createRef<FunctionBox>();
+
+ view.add(
+ <FunctionBox
+ arity={2}
+ ref={box}
+ fn={cardGeneratorFor}
+ source={cardGeneratorForSource}
+ outputFontSize={20}
+ />,
+ );
+
+ yield* all(
+ box().reset(0.1),
+ box().showCode(0.5),
+ slideTransition(Direction.Left, 0.5),
+ );
+
+ yield* beginSlide("show code");
+
+ const [alan] = PEOPLE;
+ yield* box().setInputs(
+ [{ val: alan, node: <Person person={alan} /> }, { val: "valentine" }],
+ 0.5,
+ );
+
+ yield* beginSlide("show inputs");
+
+ yield* box().hideCode(0.5);
+ yield* box().propogateInput(0.5);
+ yield* box().propogateOutput(0.5);
+
+ yield* beginSlide("create child function");
+
+ const child = box().getChild();
+ yield* child().showCode(0.5);
+
+ yield* beginSlide("show child function");
+
+ yield* child().hideCode(0.5);
+ yield* child().setInputs([{ val: "" }], 0.5);
+ yield* child().propogateInput(0.5);
+ yield* child().propogateOutput(0.5);
+
+ yield* beginSlide("propogate child function");
+});
diff --git a/src/scenes/further.meta b/src/scenes/further.meta
new file mode 100644
index 0000000..bc7d625
--- /dev/null
+++ b/src/scenes/further.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 60068077
+} \ No newline at end of file
diff --git a/src/scenes/further.tsx b/src/scenes/further.tsx
new file mode 100644
index 0000000..8758080
--- /dev/null
+++ b/src/scenes/further.tsx
@@ -0,0 +1,43 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const goingFurtherLInes = [
+ "pattern matching",
+ "the typed lambda calculus",
+ "church turing thesis",
+ "lazy vs eager loading, why we use left innermost reduction",
+ "compiling to machine code & continuation passing style as IR",
+ "monads",
+];
+
+export default makeScene2D(function* (view) {
+ const lines = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ Going Further
+ </Txt>
+ <Txt
+ ref={lines}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("Going Further");
+
+ for (const line of goingFurtherLInes) {
+ yield* lines().text(lines().text() + "\n\n" + line, 1);
+ yield* beginSlide("line - " + line);
+ }
+});
diff --git a/src/scenes/generalized.tsx b/src/scenes/generalized.tsx
index 67cbb31..a3cc841 100644
--- a/src/scenes/generalized.tsx
+++ b/src/scenes/generalized.tsx
@@ -1,4 +1,4 @@
-import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import { Layout, makeScene2D } from "@motion-canvas/2d";
import {
Direction,
all,
@@ -11,7 +11,7 @@ import { FunctionBox } from "../components/function_box";
import { PEOPLE, Person, PersonI } from "../components/person";
import { CardI, daysUntilNextDate } from "./birthday_letters";
-const valentineCardFn = (person: PersonI): CardI => {
+export const valentineCardFn = (person: PersonI): CardI => {
const valentinesDay = new Date("02/14/2024");
const message =
`Dear, ${person.name}\n.` +
@@ -21,7 +21,7 @@ const valentineCardFn = (person: PersonI): CardI => {
return { message, deliverInDays };
};
-const birthdayCardFn = (person: PersonI): CardI => {
+export const birthdayCardFn = (person: PersonI): CardI => {
const age = new Date().getFullYear() - person.birthday.getFullYear();
const ending =
({ 1: "st", 2: "nd", 3: "rd" } as Record<number, string>)[
diff --git a/src/scenes/impostor.meta b/src/scenes/impostor.meta
new file mode 100644
index 0000000..ab81c2f
--- /dev/null
+++ b/src/scenes/impostor.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 675349706
+} \ No newline at end of file
diff --git a/src/scenes/impostor.tsx b/src/scenes/impostor.tsx
new file mode 100644
index 0000000..830178a
--- /dev/null
+++ b/src/scenes/impostor.tsx
@@ -0,0 +1,134 @@
+import { Img, Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+ all,
+} from "@motion-canvas/core";
+import {
+ CodeBlock,
+ edit,
+ insert,
+ lines,
+} from "@motion-canvas/2d/lib/components/CodeBlock";
+import amogusSus from "../../public/amogus.png";
+
+const cardBuilder = `const buildCards = (
+ people: PersonI[],
+ cardGenerator: (person: PersonI) => CardI,
+): CardI[] => {
+ const cards: CardI[] = [];
+
+ for (const person of people) {
+ const card = cardGenerator(person);
+ cards.push(card);
+ }
+
+ return cards;
+};`;
+
+export default makeScene2D(function* (view) {
+ const layout = createRef<Layout>();
+
+ const buildCards = createRef<CodeBlock>();
+ const amogus = createRef<Img>();
+
+ view.add(
+ <Layout ref={layout} layout direction="row" gap={0}>
+ <CodeBlock
+ fontSize={25}
+ language="typescript"
+ ref={buildCards}
+ code={cardBuilder}
+ />
+ <Img ref={amogus} src={amogusSus} opacity={0} width={0} height={0} />
+ </Layout>,
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("show buildCards");
+
+ yield* buildCards().selection([...lines(6), ...lines(8)], 0.75);
+ yield* all(
+ amogus().width(300, 0.5),
+ amogus().height(400, 0.5),
+
+ amogus().opacity(1, 0.5),
+ layout().gap(100, 0.5),
+ );
+
+ yield* beginSlide("show side effects");
+
+ yield* all(
+ buildCards().edit(1.2)`const buildCards = (
+ people: PersonI[],
+ cardGenerator: (person: PersonI) => CardI,
+): CardI[] => {${insert(`
+ if (people.length === 0) {
+ return [];
+ }
+`)}
+ const cards: CardI[] = [];
+
+ for (const person of people) {
+ const card = cardGenerator(person);
+ cards.push(card);
+ }
+
+ return cards;
+};`,
+ amogus().width(0, 0.3),
+ amogus().height(0, 0.3),
+
+ layout().gap(0, 0.3),
+ );
+ yield* beginSlide("base case");
+
+ yield* buildCards().edit(1.2)`const buildCards = (
+ people: PersonI[],
+ cardGenerator: (person: PersonI) => CardI,
+): CardI[] => {
+ if (people.length === 0) {
+ return [];
+ }
+
+ ${edit(
+ "const cards: CardI[] = [];",
+ `const person = people[0];
+ const card = cardGenerator(person);`,
+ )}
+
+ for (const person of people) {
+ const card = cardGenerator(person);
+ cards.push(card);
+ }
+
+ return cards;
+};`;
+ yield* beginSlide("first card");
+
+ yield* buildCards().edit(1.2)`const buildCards = (
+ people: PersonI[],
+ cardGenerator: (person: PersonI) => CardI,
+): CardI[] => {
+ if (people.length === 0) {
+ return [];
+ }
+
+ const person = people[0];
+ const card = cardGenerator(person);
+
+ ${edit(
+ `for (const person of people) {
+ const card = cardGenerator(person);
+ cards.push(card);
+ }`,
+ `const restPeople = people.slice(1);
+ const cards = [card].concat(buildCards(restPeople, cardGenerator));`,
+ )}
+
+ return cards;
+};`;
+ yield* beginSlide("recursion");
+});
diff --git a/src/scenes/index.ts b/src/scenes/index.ts
index 6f09c88..1a5c5f8 100644
--- a/src/scenes/index.ts
+++ b/src/scenes/index.ts
@@ -10,18 +10,54 @@ import valentines_letters from "./valentines_letters?scene";
import birthday_letters from "./birthday_letters?scene";
import sad_people from "./sad_people?scene";
import generalized from "./generalized?scene";
+import dna from "./dna?scene";
+import function_dna from "./function_dna?scene";
+import currying from "./currying?scene";
+import currying_detail from "./currying_detail?scene";
+import impostor from "./impostor?scene";
+import pros_cons from "./pros_cons?scene";
+import parttwo from "./parttwo?scene";
+import the_lambda_calculus from "./the_lambda_calculus?scene";
+import reductions from "./reductions?scene";
+import substitution from "./substitution?scene";
+import lambda_reduction_example from "./lambda_reduction_example?scene";
+import church_encoding from "./church_encoding?scene";
+import boolean_algebra_lambda from "./boolean_algebra_lambda?scene";
+import boolean_encoding from "./boolean_encoding?scene";
+import recursion from "./recursion?scene";
+import lambda_recursion from "./lambda_recursion?scene";
+import further from "./further?scene";
+import questions from "./questions?scene";
export const scenes = [
- //title,
- //me,
- //partone,
- //flirtingwithfunctions,
- //doctor,
- //first_box,
- //hungry_partner,
- //pure_functions,
- //valentines_letters,
- //sad_people,
- //birthday_letters,
+ title,
+ me,
+ partone,
+ flirtingwithfunctions,
+ doctor,
+ first_box,
+ hungry_partner,
+ pure_functions,
+ valentines_letters,
+ sad_people,
+ birthday_letters,
generalized,
+ dna,
+ function_dna,
+ currying,
+ currying_detail,
+ impostor,
+ pros_cons,
+ parttwo,
+ the_lambda_calculus,
+ reductions,
+ substitution,
+ church_encoding,
+ lambda_reduction_example,
+ boolean_encoding,
+ boolean_algebra_lambda,
+ recursion,
+ lambda_recursion,
+ further,
+ questions,
];
diff --git a/src/scenes/lambda_recursion.meta b/src/scenes/lambda_recursion.meta
new file mode 100644
index 0000000..35466b8
--- /dev/null
+++ b/src/scenes/lambda_recursion.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 1988478153
+} \ No newline at end of file
diff --git a/src/scenes/lambda_recursion.tsx b/src/scenes/lambda_recursion.tsx
new file mode 100644
index 0000000..4a2b4a1
--- /dev/null
+++ b/src/scenes/lambda_recursion.tsx
@@ -0,0 +1,45 @@
+import { Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { LambdaReducer } from "../components/lambda_reducer";
+import { baseDefinitions } from "../utils/lambdas";
+
+export default makeScene2D(function* (view) {
+ const lambdaReducer = createRef<LambdaReducer>();
+ const layout = createRef<Layout>();
+
+ view.add(
+ <Layout
+ layout
+ ref={layout}
+ direction="column"
+ alignItems="center"
+ gap={50}
+ ></Layout>,
+ );
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("Boolean Reductions");
+
+ for (const term of ["Y", "(Y (λ y . y))"]) {
+ yield* layout().opacity(0, 0.5);
+ layout().add(
+ <LambdaReducer
+ ref={lambdaReducer}
+ lambdaTerm={term}
+ definitions={baseDefinitions}
+ ></LambdaReducer>,
+ );
+ yield* layout().opacity(1, 0.5);
+
+ yield* beginSlide("Next Reduction " + term);
+ for (let i = 0; i < 6; i++) {
+ yield* lambdaReducer().step(0.5);
+ yield* beginSlide(term + " Next Step " + i);
+ }
+ layout().removeChildren();
+ }
+});
diff --git a/src/scenes/lambda_reduction_example.meta b/src/scenes/lambda_reduction_example.meta
new file mode 100644
index 0000000..eeefd28
--- /dev/null
+++ b/src/scenes/lambda_reduction_example.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2126031881
+} \ No newline at end of file
diff --git a/src/scenes/lambda_reduction_example.tsx b/src/scenes/lambda_reduction_example.tsx
new file mode 100644
index 0000000..8f2436a
--- /dev/null
+++ b/src/scenes/lambda_reduction_example.tsx
@@ -0,0 +1,47 @@
+import { Layout, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { LambdaReducer } from "../components/lambda_reducer";
+import { baseDefinitions } from "../utils/lambdas";
+
+export default makeScene2D(function* (view) {
+ const lambdaReducer = createRef<LambdaReducer>();
+ const layout = createRef<Layout>();
+
+ view.add(
+ <Layout layout ref={layout} direction="column" alignItems="center" gap={50}>
+ <LambdaReducer
+ ref={lambdaReducer}
+ lambdaTerm={"(succ zero)"}
+ definitions={baseDefinitions}
+ ></LambdaReducer>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("Example Reductions");
+
+ for (let i = 0; !lambdaReducer().isDone(); i++) {
+ yield* lambdaReducer().step(0.5);
+ yield* beginSlide("1 Next Step " + i);
+ }
+
+ const one = lambdaReducer().getCode();
+ const reduceToTwo = createRef<LambdaReducer>();
+ layout().add(
+ <LambdaReducer
+ ref={reduceToTwo}
+ lambdaTerm={`(succ ${one})`}
+ definitions={baseDefinitions}
+ ></LambdaReducer>
+ );
+
+ for (let i = 0; !reduceToTwo().isDone(); i++) {
+ yield* reduceToTwo().step(0.5);
+ yield* beginSlide("2 Next Step " + i);
+ }
+});
diff --git a/src/scenes/me.tsx b/src/scenes/me.tsx
index 1d819e3..143d131 100644
--- a/src/scenes/me.tsx
+++ b/src/scenes/me.tsx
@@ -1,7 +1,7 @@
import { Node, Img, Txt, Layout, makeScene2D } from "@motion-canvas/2d";
import { beginSlide, createRef, all } from "@motion-canvas/core";
-import me from "../../public/img/me.jpg";
+import pengy from "../../public/img/pengy.png";
import { theme } from "../theme";
export default makeScene2D(function* (view) {
@@ -41,11 +41,11 @@ export default makeScene2D(function* (view) {
</Txt>
</Node>
</Layout>
- <Img y={-10} ref={img} src={me} width={10} alpha={0} radius={20} />{" "}
+ <Img y={-10} ref={img} src={pengy} width={10} alpha={0} radius={20} />{" "}
<Txt opacity={0} ref={src} fontFamily={theme.font} fill={theme.green.hex}>
git.simponic.xyz/simponic/compiling-the-lambda-calculus
</Txt>
- </>,
+ </>
);
yield img().fill(img().getColorAtPoint(0));
@@ -59,7 +59,7 @@ export default makeScene2D(function* (view) {
node().opacity(1, 1),
layout().position.x(diff, 1),
src().opacity(1, 1),
- src().position.y(290, 1),
+ src().position.y(290, 1)
);
yield* beginSlide("About Me");
diff --git a/src/scenes/parttwo.meta b/src/scenes/parttwo.meta
new file mode 100644
index 0000000..c18d436
--- /dev/null
+++ b/src/scenes/parttwo.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2908089933
+} \ No newline at end of file
diff --git a/src/scenes/parttwo.tsx b/src/scenes/parttwo.tsx
new file mode 100644
index 0000000..eb62e09
--- /dev/null
+++ b/src/scenes/parttwo.tsx
@@ -0,0 +1,16 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import { Direction, beginSlide, slideTransition } from "@motion-canvas/core";
+import { theme } from "../theme";
+
+export default makeScene2D(function* (view) {
+ yield view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontFamily={theme.font} fontSize={100} fill={theme.text.hex}>
+ Part Two
+ </Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("Part Two");
+});
diff --git a/src/scenes/pros_cons.meta b/src/scenes/pros_cons.meta
new file mode 100644
index 0000000..128b02e
--- /dev/null
+++ b/src/scenes/pros_cons.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 3275339858
+} \ No newline at end of file
diff --git a/src/scenes/pros_cons.tsx b/src/scenes/pros_cons.tsx
new file mode 100644
index 0000000..508c7bc
--- /dev/null
+++ b/src/scenes/pros_cons.tsx
@@ -0,0 +1,61 @@
+import { Img, Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const PROS = [
+ "readbility, reasoning",
+ "concurrency",
+ "no side effects",
+ "computers and math!",
+];
+
+const CONS = ["more computation", "higher learning curve"];
+
+export default makeScene2D(function* (view) {
+ const pros = createRef<Txt>();
+ const cons = createRef<Txt>();
+
+ view.add(
+ <Layout direction="row" justifyContent="center" gap={300} layout>
+ <Layout direction="column" justifyContent="end">
+ <Txt fontSize={30} fontFamily={theme.font} fill={theme.green.hex}>
+ PROS :)
+ </Txt>
+ <Txt
+ ref={pros}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ <Layout direction="column" justifyContent="start">
+ <Txt fontSize={30} fontFamily={theme.font} fill={theme.red.hex}>
+ CONS :(
+ </Txt>
+ <Txt
+ ref={cons}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ </Layout>,
+ );
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("layout pros and cons");
+
+ for (const pro of PROS) {
+ yield* pros().text(pros().text() + "\n\n+ " + pro, 0.5);
+ yield* beginSlide("pro - " + pro);
+ }
+
+ for (const con of CONS) {
+ yield* cons().text(cons().text() + "\n\n- " + con, 0.5);
+ yield* beginSlide("con - " + con);
+ }
+});
diff --git a/src/scenes/questions.meta b/src/scenes/questions.meta
new file mode 100644
index 0000000..c6cc2f9
--- /dev/null
+++ b/src/scenes/questions.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 3904825059
+} \ No newline at end of file
diff --git a/src/scenes/questions.tsx b/src/scenes/questions.tsx
new file mode 100644
index 0000000..16adf54
--- /dev/null
+++ b/src/scenes/questions.tsx
@@ -0,0 +1,16 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import { Direction, beginSlide, slideTransition } from "@motion-canvas/core";
+import { theme } from "../theme";
+
+export default makeScene2D(function* (view) {
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ Questions?
+ </Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("Questions");
+});
diff --git a/src/scenes/recursion.meta b/src/scenes/recursion.meta
new file mode 100644
index 0000000..b574f39
--- /dev/null
+++ b/src/scenes/recursion.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 693500437
+} \ No newline at end of file
diff --git a/src/scenes/recursion.tsx b/src/scenes/recursion.tsx
new file mode 100644
index 0000000..167dd00
--- /dev/null
+++ b/src/scenes/recursion.tsx
@@ -0,0 +1,36 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const recursion = ["Y = λ f . (λ x . f (x x)) (λ x . f (x x))"];
+
+export default makeScene2D(function* (view) {
+ const lines = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ Recursion and Combinators
+ </Txt>
+ <Txt
+ ref={lines}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("The Lambda Calculus - Church Encoding");
+
+ for (const line of recursion) {
+ yield* lines().text(lines().text() + "\n\n" + line, 1);
+ yield* beginSlide("recursion - " + line);
+ }
+});
diff --git a/src/scenes/reductions.meta b/src/scenes/reductions.meta
new file mode 100644
index 0000000..6c4e6c7
--- /dev/null
+++ b/src/scenes/reductions.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 2906227318
+} \ No newline at end of file
diff --git a/src/scenes/reductions.tsx b/src/scenes/reductions.tsx
new file mode 100644
index 0000000..5ee8961
--- /dev/null
+++ b/src/scenes/reductions.tsx
@@ -0,0 +1,40 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const reductions = [
+ "1. α - conversion: Renaming of bound variables to avoid name clashes (out of\nscope - assume user knows not to bind variable names already chosen elsewhere).",
+ "2. β - reduction: Application of a function to an argument.",
+ "3. η - reduction: Conversion of a function to a point-free form (out of scope).",
+];
+
+export default makeScene2D(function* (view) {
+ const rules = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ The Lambda Calculus - Reductions
+ </Txt>
+ <Txt
+ ref={rules}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("The Lambda Calculus - Reductions");
+
+ for (const rule of reductions) {
+ yield* rules().text(rules().text() + "\n\n" + rule, 1);
+ yield* beginSlide("reduction - " + rule);
+ }
+});
diff --git a/src/scenes/substitution.meta b/src/scenes/substitution.meta
new file mode 100644
index 0000000..56299b4
--- /dev/null
+++ b/src/scenes/substitution.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 3113568447
+} \ No newline at end of file
diff --git a/src/scenes/substitution.tsx b/src/scenes/substitution.tsx
new file mode 100644
index 0000000..1e7e48c
--- /dev/null
+++ b/src/scenes/substitution.tsx
@@ -0,0 +1,45 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const substitution = [
+ "β-reduce [ (λ x . x) y ] => y\n\n",
+ "Formal definition:",
+ "1. x[x := N] = N",
+ "2. y[x := N] = y if y != x",
+ "3. (M N)[x := P] = (M[x := P]) (N[x := P])",
+ "4. (λ x . M)[x := N] = λ x . M",
+ "5. (λ y . M)[x := N] = λ y . (M[x := N]) if y != x and y is not _free_ in N",
+ " +=> A variable is _free_ in a lambda term if it is not bound by a λ abstraction.",
+];
+
+export default makeScene2D(function* (view) {
+ const rules = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ The Lambda Calculus - Substitution Rules
+ </Txt>
+ <Txt
+ ref={rules}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("The Lambda Calculus - Substitutions");
+
+ for (const rule of substitution) {
+ yield* rules().text(rules().text() + "\n\n" + rule, 1);
+ yield* beginSlide("substitution - " + rule);
+ }
+});
diff --git a/src/scenes/the_lambda_calculus.meta b/src/scenes/the_lambda_calculus.meta
new file mode 100644
index 0000000..56b46d0
--- /dev/null
+++ b/src/scenes/the_lambda_calculus.meta
@@ -0,0 +1,5 @@
+{
+ "version": 0,
+ "timeEvents": [],
+ "seed": 561758562
+} \ No newline at end of file
diff --git a/src/scenes/the_lambda_calculus.tsx b/src/scenes/the_lambda_calculus.tsx
new file mode 100644
index 0000000..7a3e692
--- /dev/null
+++ b/src/scenes/the_lambda_calculus.tsx
@@ -0,0 +1,40 @@
+import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
+import {
+ Direction,
+ beginSlide,
+ createRef,
+ slideTransition,
+} from "@motion-canvas/core";
+import { theme } from "../theme";
+
+const lambdaRules = [
+ '1. "x": A variable is a character or string representing a parameter, and is a valid lambda term.',
+ '2. "(λ x . t)" is an "abstraction" - a function definition, taking as input the \nbound variable x and returning the lambda term t.',
+ '3. (M N) is an "application", applying a lambda term M with a lambda term N.',
+];
+
+export default makeScene2D(function* (view) {
+ const rules = createRef<Txt>();
+
+ view.add(
+ <Layout layout direction="column" alignItems="center">
+ <Txt fontSize={40} fontFamily={theme.font} fill={theme.text.hex}>
+ The Lambda Calculus
+ </Txt>
+ <Txt
+ ref={rules}
+ fontSize={30}
+ fontFamily={theme.font}
+ fill={theme.text.hex}
+ ></Txt>
+ </Layout>
+ );
+
+ yield* slideTransition(Direction.Right);
+ yield* beginSlide("The Lambda Calculus");
+
+ for (const rule of lambdaRules) {
+ yield* rules().text(rules().text() + "\n\n" + rule, 1);
+ yield* beginSlide("rule - " + rule);
+ }
+});