add generatlized
This commit is contained in:
parent
c55d9d2832
commit
512c245466
35
script.md
35
script.md
@ -105,36 +105,11 @@ There, now, we can make sure our friends are happy on their birthdays!
|
|||||||
|
|
||||||
But, this is getting annoying; what about Christmas, Thanksgiving, or Easter? Making a new black box to make a list of new cards, going through each person, every single time to construct a list of cards, is getting really tedious.
|
But, this is getting annoying; what about Christmas, Thanksgiving, or Easter? Making a new black box to make a list of new cards, going through each person, every single time to construct a list of cards, is getting really tedious.
|
||||||
|
|
||||||
What if we generalized this? We create a bunch of black boxes that take a person, and generate them a card, specifically; like a template for a card you could print off and fill in manually.
|
[SPACE] What if we generalized this? [SPACE] We create a couple of black boxes that take a person, and generate them a card, specifically; like a template for a card you could print off and fill in manually. Like this, for alan turing.
|
||||||
|
|
||||||
```python
|
Then, we can use a new black box that takes a list of people, and applies this template to each person.
|
||||||
def valentine_letter(person):
|
|
||||||
return f"Dear, {person.name}\nYour smile lights up my world. Happy Valentine's Day!")
|
|
||||||
|
|
||||||
def birthday_card(person):
|
The ability in a language to pass a function around like this - like a variable - is what makes functions "first class". And the `buildCards` function takes a function as input, making it a "higher order function".
|
||||||
today = new Date()
|
|
||||||
daysUntilBirthday = toDays(new Date(person.birthday, today.year) - today)
|
|
||||||
newAge = today.year - person.birthday.year
|
|
||||||
|
|
||||||
card = f"Happy Birthday {name}\nI can't believe you're already {newAge} years old!"
|
|
||||||
cards.append({ "message": card, "deliverInDays": daysUntilBirthday })
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, we can use a black box that takes a list of people, and applies this template to each person.
|
|
||||||
|
|
||||||
```
|
|
||||||
def buildCards(people, cardMaker):
|
|
||||||
cards = []
|
|
||||||
for person in people:
|
|
||||||
card = cardMaker(person)
|
|
||||||
cards.append(card)
|
|
||||||
return cards
|
|
||||||
|
|
||||||
people = [{"name": "Joseph", birthday: new Date()}, {"name": "DeeDee", birthday: new Date()}]
|
|
||||||
buildCards(people, birthdayCard)
|
|
||||||
```
|
|
||||||
|
|
||||||
The ability in a language to pass a function around like this - like a variable - is what makes functions "first class". And the `buildCards` function takes a function as input, making it a "higher order function". (TODO: slides)
|
|
||||||
|
|
||||||
Functional Reproduction
|
Functional Reproduction
|
||||||
===
|
===
|
||||||
@ -211,7 +186,7 @@ Immutability
|
|||||||
===
|
===
|
||||||
We briefly mentioned side effects and alluded them to the unpredictability of a partner. We love our black boxes because they're reliable.
|
We briefly mentioned side effects and alluded them to the unpredictability of a partner. We love our black boxes because they're reliable.
|
||||||
|
|
||||||
But, we've actually had an impostor among us (AMOGUS sound??) throughout this presentation. Specifically in ~buildCards~:
|
But, we've actually had an impostor among us (AMOGUS sound??) throughout this presentation. Specifically in `buildCards`:
|
||||||
|
|
||||||
```
|
```
|
||||||
def buildCards(people, cardMaker):
|
def buildCards(people, cardMaker):
|
||||||
@ -244,7 +219,7 @@ def build_cards(people, card_maker):
|
|||||||
return [card] + build_cards(rest_people, card_maker)
|
return [card] + build_cards(rest_people, card_maker)
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we're not changing anything at all (except the stack), with the same functionality; this code is "immutable". When we call ~build_cards~ on a list of people, we're 100% certain we're not gonna get something odd short of a bug.
|
Here we're not changing anything at all (except the stack), with the same functionality; this code is "immutable". When we call `build_cards` on a list of people, we're 100% certain we're not gonna get something odd short of a bug.
|
||||||
|
|
||||||
At a high level there are so many benefits to immutability:
|
At a high level there are so many benefits to immutability:
|
||||||
+ Concurrency (TODO: go into more detail)
|
+ Concurrency (TODO: go into more detail)
|
||||||
|
@ -86,7 +86,7 @@ export class FunctionBox extends Node {
|
|||||||
alignItems={"center"}
|
alignItems={"center"}
|
||||||
layout
|
layout
|
||||||
>
|
>
|
||||||
<Rect direction={"column"} alignItems={"end"}>
|
<Rect direction={"column"} alignItems={"end"} gap={10}>
|
||||||
{range(this.arity).map((i) => (
|
{range(this.arity).map((i) => (
|
||||||
<Rect direction={"row"} alignItems={"center"} gap={10}>
|
<Rect direction={"row"} alignItems={"center"} gap={10}>
|
||||||
<Rect
|
<Rect
|
||||||
@ -116,8 +116,9 @@ export class FunctionBox extends Node {
|
|||||||
fill={theme.crust.hex}
|
fill={theme.crust.hex}
|
||||||
lineWidth={4}
|
lineWidth={4}
|
||||||
padding={60}
|
padding={60}
|
||||||
direction={"row"}
|
direction="row"
|
||||||
height={"100%"}
|
height="100%"
|
||||||
|
alignItems="center"
|
||||||
>
|
>
|
||||||
<Txt fontFamily={theme.font} fill={theme.text.hex} ref={this.boxMoji}>
|
<Txt fontFamily={theme.font} fill={theme.text.hex} ref={this.boxMoji}>
|
||||||
{this.idlingText}
|
{this.idlingText}
|
||||||
@ -273,7 +274,6 @@ export class FunctionBox extends Node {
|
|||||||
<CodeBlock
|
<CodeBlock
|
||||||
fontFamily={theme.font}
|
fontFamily={theme.font}
|
||||||
language="typescript"
|
language="typescript"
|
||||||
fontSize={this.outputFontSize}
|
|
||||||
code={JSON.stringify(output, null, 2)}
|
code={JSON.stringify(output, null, 2)}
|
||||||
></CodeBlock>,
|
></CodeBlock>,
|
||||||
);
|
);
|
||||||
|
@ -13,13 +13,13 @@ import { FunctionBox } from "../components/function_box";
|
|||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { PEOPLE, Person, PersonI } from "../components/person";
|
import { PEOPLE, Person, PersonI } from "../components/person";
|
||||||
|
|
||||||
const daysUntilNextBirthday = (birthDate: Date): number => {
|
export const daysUntilNextDate = (date: Date): number => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
||||||
const nextBirthday = new Date(
|
const nextBirthday = new Date(
|
||||||
today.getFullYear(),
|
today.getFullYear(),
|
||||||
birthDate.getMonth(),
|
date.getMonth(),
|
||||||
birthDate.getDate(),
|
date.getDate(),
|
||||||
);
|
);
|
||||||
if (today > nextBirthday) nextBirthday.setFullYear(today.getFullYear() + 1);
|
if (today > nextBirthday) nextBirthday.setFullYear(today.getFullYear() + 1);
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ export const birthdayCardsFor = (people: PersonI[]): CardI[] => {
|
|||||||
`Happy ${age}${ending} birthday, ${person.name}!\n` +
|
`Happy ${age}${ending} birthday, ${person.name}!\n` +
|
||||||
"I can't believe it's already been a year!";
|
"I can't believe it's already been a year!";
|
||||||
|
|
||||||
const deliverInDays = daysUntilNextBirthday(person.birthday);
|
const deliverInDays = daysUntilNextDate(person.birthday);
|
||||||
cards.push({ deliverInDays, message });
|
cards.push({ deliverInDays, message });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ const birthdayCardsFor = (people: PersonI[]): CardI[] => {
|
|||||||
\`Happy \${age}\${ageEnding} birthday, \${person.name}!\\n\` +
|
\`Happy \${age}\${ageEnding} birthday, \${person.name}!\\n\` +
|
||||||
"I can't believe it's already been a year!";
|
"I can't believe it's already been a year!";
|
||||||
|
|
||||||
const deliverInDays = daysUntilNextBirthday(person.birthday);
|
const deliverInDays = daysUntilNextDate(person.birthday);
|
||||||
cards.push({ deliverInDays, message });
|
cards.push({ deliverInDays, message });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
src/scenes/generalized.meta
Normal file
5
src/scenes/generalized.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"version": 0,
|
||||||
|
"timeEvents": [],
|
||||||
|
"seed": 3138224359
|
||||||
|
}
|
212
src/scenes/generalized.tsx
Normal file
212
src/scenes/generalized.tsx
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
|
||||||
|
import {
|
||||||
|
Direction,
|
||||||
|
all,
|
||||||
|
beginSlide,
|
||||||
|
createRef,
|
||||||
|
slideTransition,
|
||||||
|
} from "@motion-canvas/core";
|
||||||
|
|
||||||
|
import { FunctionBox } from "../components/function_box";
|
||||||
|
import { PEOPLE, Person, PersonI } from "../components/person";
|
||||||
|
import { CardI, daysUntilNextDate } from "./birthday_letters";
|
||||||
|
|
||||||
|
const valentineCardFn = (person: PersonI): CardI => {
|
||||||
|
const valentinesDay = new Date("02/14/2024");
|
||||||
|
const message =
|
||||||
|
`Dear, ${person.name}\n.` +
|
||||||
|
"Your smile lights up my world.\n" +
|
||||||
|
"Happy Valentine's Day!";
|
||||||
|
const deliverInDays = daysUntilNextDate(valentinesDay);
|
||||||
|
return { message, deliverInDays };
|
||||||
|
};
|
||||||
|
|
||||||
|
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>)[
|
||||||
|
parseInt(Array.from(age.toString()).at(-1))
|
||||||
|
] ?? "th";
|
||||||
|
const message =
|
||||||
|
`Happy ${age}${ending} birthday, ${person.name}!\n` +
|
||||||
|
"I can't believe it's already been a year!";
|
||||||
|
|
||||||
|
const deliverInDays = daysUntilNextDate(person.birthday);
|
||||||
|
return { deliverInDays, message };
|
||||||
|
};
|
||||||
|
|
||||||
|
const valentineCardGenerator = `const valentineCardGenerator = (person: PersonI): CardI => {
|
||||||
|
const valentinesDay = new Date("02/14/2024");
|
||||||
|
const message =
|
||||||
|
\`Dear, \${person.name}\\n.\` +
|
||||||
|
"Your smile lights up my world.\\n" +
|
||||||
|
"Happy Valentine's Day!";
|
||||||
|
const deliverInDays = daysUntilNextDate(valentinesDay);
|
||||||
|
return { message, deliverInDays };
|
||||||
|
};`;
|
||||||
|
|
||||||
|
const birthdayCardGenerator = `const birthdayCardGenerator = (person: PersonI): CardI => {
|
||||||
|
const age = new Date().getFullYear() - person.birthday.getFullYear();
|
||||||
|
const ageEnding = (
|
||||||
|
{ 1: "st", 2: "nd", 3: "rd" } as Record<number, string>
|
||||||
|
)[parseInt(Array.from(age.toString()).at(-1))] ?? "th";
|
||||||
|
|
||||||
|
const message =
|
||||||
|
\`Happy \${age}\${ageEnding} birthday, \${person.name}!\\n\` +
|
||||||
|
"I can't believe it's already been a year!";
|
||||||
|
|
||||||
|
const deliverInDays = daysUntilNextDate(person.birthday);
|
||||||
|
return { deliverInDays, message };
|
||||||
|
}`;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
buildCards;`;
|
||||||
|
|
||||||
|
export default makeScene2D(function* (view) {
|
||||||
|
const valentineFunctionBox = createRef<FunctionBox>();
|
||||||
|
const birthdayFunctionBox = createRef<FunctionBox>();
|
||||||
|
const cardBuilderBox = createRef<FunctionBox>();
|
||||||
|
const layout = createRef<Layout>();
|
||||||
|
|
||||||
|
view.add(
|
||||||
|
<Layout direction="row" gap={200} ref={layout} layout>
|
||||||
|
<Layout direction="column" alignItems="center" gap={20}>
|
||||||
|
<FunctionBox
|
||||||
|
ref={valentineFunctionBox}
|
||||||
|
source={valentineCardGenerator}
|
||||||
|
fn={valentineCardFn}
|
||||||
|
idlingText="❤️"
|
||||||
|
workingText="📝⚙"
|
||||||
|
outputFontSize={15}
|
||||||
|
></FunctionBox>
|
||||||
|
<FunctionBox
|
||||||
|
ref={birthdayFunctionBox}
|
||||||
|
source={birthdayCardGenerator}
|
||||||
|
fn={birthdayCardFn}
|
||||||
|
idlingText="🎂"
|
||||||
|
workingText="📝⚙"
|
||||||
|
outputFontSize={15}
|
||||||
|
></FunctionBox>
|
||||||
|
</Layout>
|
||||||
|
<Layout direction="column" gap={20}>
|
||||||
|
<FunctionBox
|
||||||
|
ref={cardBuilderBox}
|
||||||
|
source={cardBuilder}
|
||||||
|
idlingText="🏭"
|
||||||
|
workingText="📝⚙"
|
||||||
|
outputFontSize={15}
|
||||||
|
arity={2}
|
||||||
|
></FunctionBox>
|
||||||
|
</Layout>
|
||||||
|
</Layout>,
|
||||||
|
);
|
||||||
|
|
||||||
|
yield* all(
|
||||||
|
slideTransition(Direction.Left),
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox, cardBuilderBox].map((x) =>
|
||||||
|
x().reset(0.1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
yield* beginSlide("show all functions");
|
||||||
|
|
||||||
|
yield* all(
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
|
||||||
|
x().showCode(0.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
yield* beginSlide("show generator functions");
|
||||||
|
|
||||||
|
const [p1, p2, p3, p4] = PEOPLE;
|
||||||
|
yield* all(
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
|
||||||
|
x().hideCode(0.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
yield* all(
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
|
||||||
|
x().setInputs([{ val: p2, node: <Person person={p2} /> }], 0.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
yield* beginSlide("show inputs");
|
||||||
|
|
||||||
|
yield* all(
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
|
||||||
|
x().propogateInput(0.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
yield* all(
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
|
||||||
|
x().propogateOutput(0.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
yield* beginSlide("make cards");
|
||||||
|
|
||||||
|
yield* all(
|
||||||
|
...[valentineFunctionBox, birthdayFunctionBox].map((x) => x().reset(0.5)),
|
||||||
|
cardBuilderBox().showCode(0.5),
|
||||||
|
);
|
||||||
|
|
||||||
|
yield* beginSlide("hide cards, show card generator");
|
||||||
|
|
||||||
|
yield* cardBuilderBox().setInputs(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
val: [p1, p2],
|
||||||
|
node: (
|
||||||
|
<Layout direction="row" gap={20}>
|
||||||
|
<Person person={p1} />
|
||||||
|
<Person person={p2} />
|
||||||
|
</Layout>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ val: valentineCardFn, node: valentineFunctionBox() },
|
||||||
|
],
|
||||||
|
0.5,
|
||||||
|
);
|
||||||
|
yield* beginSlide("input function to function");
|
||||||
|
|
||||||
|
yield* cardBuilderBox().hideCode(0.5);
|
||||||
|
yield* cardBuilderBox().propogateInput(0.5);
|
||||||
|
yield* cardBuilderBox().propogateOutput(0.5);
|
||||||
|
|
||||||
|
yield* beginSlide("build valentines cards");
|
||||||
|
|
||||||
|
yield* all(layout().gap(0, 0.5), cardBuilderBox().reset(0.5));
|
||||||
|
yield* cardBuilderBox().setInputs(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
val: [p2, p3, p4],
|
||||||
|
node: (
|
||||||
|
<Layout direction="row" gap={20}>
|
||||||
|
<Person person={p2} />
|
||||||
|
<Person person={p3} />
|
||||||
|
<Person person={p4} />
|
||||||
|
</Layout>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ val: birthdayCardFn, node: birthdayFunctionBox() },
|
||||||
|
],
|
||||||
|
0.5,
|
||||||
|
);
|
||||||
|
yield* beginSlide("show birthday cards input");
|
||||||
|
|
||||||
|
yield* cardBuilderBox().propogateInput(0.5);
|
||||||
|
yield* cardBuilderBox().propogateOutput(0.5);
|
||||||
|
|
||||||
|
yield* beginSlide("build cards");
|
||||||
|
});
|
@ -9,6 +9,7 @@ import pure_functions from "./pure_functions?scene";
|
|||||||
import valentines_letters from "./valentines_letters?scene";
|
import valentines_letters from "./valentines_letters?scene";
|
||||||
import birthday_letters from "./birthday_letters?scene";
|
import birthday_letters from "./birthday_letters?scene";
|
||||||
import sad_people from "./sad_people?scene";
|
import sad_people from "./sad_people?scene";
|
||||||
|
import generalized from "./generalized?scene";
|
||||||
|
|
||||||
export const scenes = [
|
export const scenes = [
|
||||||
//title,
|
//title,
|
||||||
@ -20,6 +21,7 @@ export const scenes = [
|
|||||||
//hungry_partner,
|
//hungry_partner,
|
||||||
//pure_functions,
|
//pure_functions,
|
||||||
//valentines_letters,
|
//valentines_letters,
|
||||||
sad_people,
|
//sad_people,
|
||||||
birthday_letters,
|
//birthday_letters,
|
||||||
|
generalized,
|
||||||
];
|
];
|
||||||
|
Loading…
Reference in New Issue
Block a user