diff --git a/script.md b/script.md index d1ab35d..0a1964e 100644 --- a/script.md +++ b/script.md @@ -59,15 +59,25 @@ We're in love with its predictability, the assurance that no matter what we give But let's imagine, for a moment, a different kind of relationship. One where actions outside the relationship influences responses. -Imagine asking your partner about what food they want to eat. But instead of a straightforward answer based on your question alone and some state (i.e. hunger levels, craving ratios, etc), the function's response is influenced by other factors; the day of the week, and the state of the day or week prior. We can simulate this: (go through some ratios and outputs). +Imagine asking your partner about what food they want to eat. But instead of a straightforward answer based on your question alone and some state (i.e. hunger levels, craving ratios, etc), the function's response is influenced by other factors; the day of the week, and the state of the day or week prior. We can simulate this: ((go through the ratios and outputs)). Let's see what causes this in this black box we don't love; don't pay attention to the implementation (there's some stuff we haven't talked about yet), but check out this line (MATH.RANDOM). This is a side effect; an unpredictible effect on the output. -Side effects introduce unpredictability into our programming relationships. Where output is not just determined by its input but also by the state of the outside world, or the system at the time of execution. Suddenly, the predictability we cherished is compromised. (we'll go much more in depth about this more later) +Side effects introduce unpredictability into our programming relationships. Where output is not just determined by its input but also by the state of the outside world, or the system at the time of execution. Suddenly, the predictability we cherished is compromised. -So let's take our love of this function and begin studying it. +We call a function that is unpredictable, or has side effects, "impure", and one that isn't - "pure". -We love our black boxes a lot, and we want to share them with other people in our lives. So let's create another that takes a list of people and creates a custom letter for them. +It was obvious how we could cause unpredictability by including randomness. On the left we have two impure functions. + +When we execute the first block, we get the expected result of `fib(5)`. + +But because `fact` uses the same cache, we'll run fact(5)... `fact(5)` returns fib(5)! + +Now, when I go and update the cache to be correct, we get the correct answer. I was able to change the behavior of the function by modifying stuff outside of it. Get the gist - impure vs pure functions, side effects, etc? Cool. + +For now let's move back to studying our pure black boxes. + +We love our black boxes a lot, and we want to share them with other people in our lives. So let's create another that takes a list of people and creates a custom valentine's letter for them. ```python def make_valentines_letters(people): diff --git a/src/components/function_box.tsx b/src/components/function_box.tsx index 43d3985..dc00a24 100644 --- a/src/components/function_box.tsx +++ b/src/components/function_box.tsx @@ -133,8 +133,13 @@ export class FunctionBox extends Node { - - + + - all(x.opacity(0, duration), x.fontSize(0, duration)), + all(x.opacity(1, duration), x.fontSize(this.inputFontSize, duration)), ), ...this.inputSegments.map((segment) => all(segment.points([], duration), segment.opacity(1, duration)), @@ -232,14 +237,13 @@ export class FunctionBox extends Node { public *propogateOutput(duration: number) { yield* all( - this.boxMoji().text(this.idlingText, duration), this.child()?.opacity(0.2, duration), this.output().opacity(0.2, duration), + this.output().fontSize(this.outputFontSize, duration), this.outputSegment().opacity(0, duration), ); const output = this.function(...this.currentArgs.map((input) => input.val)); - switch (typeof output) { case "function": yield this.output().add( @@ -271,6 +275,7 @@ export class FunctionBox extends Node { } yield* all( + this.boxMoji().text(this.idlingText, duration), this.outputSegment().points( [ { x: 0, y: 0 }, diff --git a/src/scenes/index.ts b/src/scenes/index.ts index d21da3b..8544e23 100644 --- a/src/scenes/index.ts +++ b/src/scenes/index.ts @@ -5,13 +5,15 @@ import flirtingwithfunctions from "./flirtingwithfunctions?scene"; import doctor from "./doctor?scene"; import first_box from "./first_box?scene"; import hungry_partner from "./hungry_partner?scene"; +import pure_functions from "./pure_functions?scene"; export const scenes = [ - // title, - // me, - // partone, - // flirtingwithfunctions, - // doctor, - // first_box, + title, + me, + partone, + flirtingwithfunctions, + doctor, + first_box, hungry_partner, + pure_functions, ]; diff --git a/src/scenes/pure_functions.meta b/src/scenes/pure_functions.meta new file mode 100644 index 0000000..c012917 --- /dev/null +++ b/src/scenes/pure_functions.meta @@ -0,0 +1,5 @@ +{ + "version": 0, + "timeEvents": [], + "seed": 1453873557 +} \ No newline at end of file diff --git a/src/scenes/pure_functions.tsx b/src/scenes/pure_functions.tsx new file mode 100644 index 0000000..c7e1f35 --- /dev/null +++ b/src/scenes/pure_functions.tsx @@ -0,0 +1,104 @@ +import { Node, Rect, Txt, makeScene2D } from "@motion-canvas/2d"; +import { + Direction, + all, + beginSlide, + createRef, + slideTransition, +} from "@motion-canvas/core"; + +import { FunctionBox } from "../components/function_box"; +import { theme } from "../theme"; + +const pureFunction = `const pureFib = (n: number) => { + if (n <= 1) { + retun 1; + } + return fib(n - 1) + fib(n - 2); +}; +pureFib;`; + +const impureFibFunction = `window.cache = [1, 1]; +const impureFib = (n: number) => { + while (cache.length <= n + 1) + cache.push(cache.at(-1) + cache.at(-2)); + return cache[n]; +}; +impureFib;`; +const impureFactFunction = `const impureFact = (n: number): number => { + while (cache.length <= n) + cache.push(cache.length * cache[cache.length - 1]); + return cache[n]; +}; +impureFact;`; + +export default makeScene2D(function* (view) { + const impureFibFunctionBox = createRef(); + const impureFactFunctionBox = createRef(); + const pureFunctionBox = createRef(); + + view.add( + + + + IMPURE + + + + + + + PURE + + + + , + ); + + yield* slideTransition(Direction.Right); + yield* beginSlide("Pure vs Impure"); + + yield* all( + impureFibFunctionBox().showCode(0.5), + impureFactFunctionBox().showCode(0.5), + ); + + yield* impureFibFunctionBox().setInputs([{ val: 5 }], 0.05); + yield* beginSlide("Show FibImpure(5)"); + + yield* impureFibFunctionBox().propogateInput(0.05); + yield* impureFibFunctionBox().propogateOutput(0.05); + yield* beginSlide("FibImpure(5)"); + + yield* impureFactFunctionBox().setInputs([{ val: 5 }], 0.05); + yield* beginSlide("Show FactImpure(5)"); + + yield* impureFactFunctionBox().propogateInput(0.05); + yield* impureFactFunctionBox().propogateOutput(0.05); + yield* beginSlide("FactImpure(5)"); + + yield* impureFactFunctionBox().reset(0.15); + yield* impureFactFunctionBox().setInputs([{ val: 5 }], 0.15); + yield* beginSlide("FactImpure(5) Add 5"); + yield* impureFactFunctionBox().propogateInput(0.05); + yield* impureFactFunctionBox().propogateOutput(0.05); + yield* beginSlide("FactImpure(5) Correct"); +});