diff --git a/script.md b/script.md index 585d74e..088ed0f 100644 --- a/script.md +++ b/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. -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 -def valentine_letter(person): - return f"Dear, {person.name}\nYour smile lights up my world. Happy Valentine's Day!") +Then, we can use a new black box that takes a list of people, and applies this template to each person. -def birthday_card(person): - 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) +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". 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. -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): @@ -244,7 +219,7 @@ def build_cards(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: + Concurrency (TODO: go into more detail) diff --git a/src/components/function_box.tsx b/src/components/function_box.tsx index b2221b4..e1ed497 100644 --- a/src/components/function_box.tsx +++ b/src/components/function_box.tsx @@ -86,7 +86,7 @@ export class FunctionBox extends Node { alignItems={"center"} layout > - + {range(this.arity).map((i) => ( {this.idlingText} @@ -273,7 +274,6 @@ export class FunctionBox extends Node { , ); diff --git a/src/scenes/birthday_letters.tsx b/src/scenes/birthday_letters.tsx index 2a63360..8fe7990 100644 --- a/src/scenes/birthday_letters.tsx +++ b/src/scenes/birthday_letters.tsx @@ -13,13 +13,13 @@ import { FunctionBox } from "../components/function_box"; import { theme } from "../theme"; import { PEOPLE, Person, PersonI } from "../components/person"; -const daysUntilNextBirthday = (birthDate: Date): number => { +export const daysUntilNextDate = (date: Date): number => { const today = new Date(); const nextBirthday = new Date( today.getFullYear(), - birthDate.getMonth(), - birthDate.getDate(), + date.getMonth(), + date.getDate(), ); 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` + "I can't believe it's already been a year!"; - const deliverInDays = daysUntilNextBirthday(person.birthday); + const deliverInDays = daysUntilNextDate(person.birthday); cards.push({ deliverInDays, message }); } @@ -70,7 +70,7 @@ const birthdayCardsFor = (people: PersonI[]): CardI[] => { \`Happy \${age}\${ageEnding} birthday, \${person.name}!\\n\` + "I can't believe it's already been a year!"; - const deliverInDays = daysUntilNextBirthday(person.birthday); + const deliverInDays = daysUntilNextDate(person.birthday); cards.push({ deliverInDays, message }); } diff --git a/src/scenes/generalized.meta b/src/scenes/generalized.meta new file mode 100644 index 0000000..46b4f46 --- /dev/null +++ b/src/scenes/generalized.meta @@ -0,0 +1,5 @@ +{ + "version": 0, + "timeEvents": [], + "seed": 3138224359 +} \ No newline at end of file diff --git a/src/scenes/generalized.tsx b/src/scenes/generalized.tsx new file mode 100644 index 0000000..67cbb31 --- /dev/null +++ b/src/scenes/generalized.tsx @@ -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)[ + 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 + )[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(); + const birthdayFunctionBox = createRef(); + const cardBuilderBox = createRef(); + const layout = createRef(); + + view.add( + + + + + + + + + , + ); + + 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: }], 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: ( + + + + + ), + }, + { 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: ( + + + + + + ), + }, + { 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"); +}); diff --git a/src/scenes/index.ts b/src/scenes/index.ts index 8b53e09..6f09c88 100644 --- a/src/scenes/index.ts +++ b/src/scenes/index.ts @@ -9,6 +9,7 @@ import pure_functions from "./pure_functions?scene"; 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"; export const scenes = [ //title, @@ -20,6 +21,7 @@ export const scenes = [ //hungry_partner, //pure_functions, //valentines_letters, - sad_people, - birthday_letters, + //sad_people, + //birthday_letters, + generalized, ];