update
This commit is contained in:
parent
5b8b3abcba
commit
05572d8404
18
script.md
18
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):
|
||||
|
@ -133,8 +133,13 @@ export class FunctionBox extends Node {
|
||||
</Node>
|
||||
</Rect>
|
||||
|
||||
<Rect direction={"column"} height={"100%"} alignItems={"end"}>
|
||||
<Rect direction={"row"} alignItems={"center"} gap={10}>
|
||||
<Rect
|
||||
direction="column"
|
||||
height={"100%"}
|
||||
alignItems={"end"}
|
||||
justifyContent="center"
|
||||
>
|
||||
<Rect direction="row" alignItems="center" gap={10}>
|
||||
<Line
|
||||
points={[]}
|
||||
stroke={theme.red.hex}
|
||||
@ -159,7 +164,7 @@ export class FunctionBox extends Node {
|
||||
public *resetInput(duration: number) {
|
||||
yield* all(
|
||||
...this.inputs.map((x) =>
|
||||
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 },
|
||||
|
@ -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,
|
||||
];
|
||||
|
5
src/scenes/pure_functions.meta
Normal file
5
src/scenes/pure_functions.meta
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": 0,
|
||||
"timeEvents": [],
|
||||
"seed": 1453873557
|
||||
}
|
104
src/scenes/pure_functions.tsx
Normal file
104
src/scenes/pure_functions.tsx
Normal file
@ -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<FunctionBox>();
|
||||
const impureFactFunctionBox = createRef<FunctionBox>();
|
||||
const pureFunctionBox = createRef<FunctionBox>();
|
||||
|
||||
view.add(
|
||||
<Rect direction="row" gap={300} layout>
|
||||
<Rect direction="column" alignItems="center" gap={20}>
|
||||
<Txt fontSize={30} fontFamily={theme.font} fill={theme.text.hex}>
|
||||
IMPURE
|
||||
</Txt>
|
||||
<FunctionBox
|
||||
arity={1}
|
||||
idlingText=""
|
||||
workingText=""
|
||||
source={impureFibFunction}
|
||||
ref={impureFibFunctionBox}
|
||||
/>
|
||||
<FunctionBox
|
||||
arity={1}
|
||||
idlingText=""
|
||||
workingText=""
|
||||
source={impureFactFunction}
|
||||
ref={impureFactFunctionBox}
|
||||
/>
|
||||
</Rect>
|
||||
<Rect direction="column" alignItems="center" gap={20}>
|
||||
<Txt fontSize={30} fontFamily={theme.font} fill={theme.text.hex}>
|
||||
PURE
|
||||
</Txt>
|
||||
<FunctionBox
|
||||
arity={1}
|
||||
idlingText=""
|
||||
workingText=""
|
||||
source={pureFunction}
|
||||
ref={pureFunctionBox}
|
||||
/>
|
||||
</Rect>
|
||||
</Rect>,
|
||||
);
|
||||
|
||||
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");
|
||||
});
|
Loading…
Reference in New Issue
Block a user