This commit is contained in:
Elizabeth Hunt 2024-02-11 16:38:36 -07:00
parent 609338de80
commit 9db4283a20
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
5 changed files with 78 additions and 66 deletions

View File

@ -3,7 +3,7 @@
"private": true,
"version": "0.0.0",
"scripts": {
"start": "vite",
"start": "vite --host",
"serve": "vite",
"build": "tsc && vite build"
},

View File

@ -3,7 +3,7 @@ About Me
"For the new faces, I'm Elizabeth, or simponic on the discord..."
- I love functional programming; I've been enjoying programs functionally for over 3 years; in LISP and Elixir mostly
- I love functional programming; I've been enjoying programs functionally for over 3 years; in LISP and Elixir mostly. I've loved every second of it. Well, maybe not every second, bust definitely most of them.
- Soon to be SDE at AWS
- I'm 20 years old, graduating this semester once I'm done with my final general class I missed on my grad plan (2credits only, ugh, ask me after if you want to hear the bureacracy)
- I was president of the USU Linux club from 2021 - 2024
@ -11,16 +11,11 @@ About Me
Of course this presentation is open source at the link you see on the board.
Part One
===
"But you didn't come here to meet me; and we don't have much time to get through everything. So let's start. Part one: Flirting With Functions!"
Flirting With Functions
===
Tomorrow's Valentine's day, but you realize; you don't have a Valentine!
Desparate to make yourself feel better, you turn to your computer and open Emacs, querying "m-x doctor".
Desparate to make yourself feel better, you turn to your computer and open Emacs, asking the M-x doctor for help.
```
I am the psychotherapist. Please, describe your problems. Each time you are finished talking, type RET twice.
@ -41,23 +36,23 @@ Yes, hmmm... so, do you really think this is so?
> yes
```
well that's not super helpful, looks like the "AI repeating itself" notion is nothing modern.
well that's not super helpful, looks like the "AI stuck in a loop repeating itself" notion is nothing modern.
On our journey to get a valentine, looks like we have stumbled across a black box. What does it do? Well... we could start shoving random numbers in it and see what happens.
On our journey to get a valentine, it looks like we have stumbled across a black box. Why? Well... we could start shoving random numbers in it and see what happens.
hmm... [-1, 2]? okay, 1. [3, 4]? okay, 7. what if we try [-1, 2] again, see if it meets our criteria to our valentine. amazing!
hmm... [-1, 2]? okay, 1. [3, 4]? okay, 7. what if we try [-1, 2] again, see if it meets our criteria to be our valentine; not changing its answer. amazing!
No matter how many times we put two numbers in it gives me the same answer; we're in love with it already!
So we're ready to start getting to know this black box. Let's look at what's behind this black box.
Let's look at what's behind this black box, see if there's more we can get to know.
Now where could our curiosity take us?
Where could our curiosity take us?
Ah. A simple add function.
A simple add function. That makes sense.
We're in love with its predictability, the assurance that no matter what we give as input or how many times it's given, the function behaves in a consistent manner.
We're in love with its predictability, and simplicity; the assurance that no matter what we give as input or how many times it's given, the function behaves in a consistent manner.
But let's imagine, for a moment, a different kind of relationship. One where actions outside the relationship influences responses.
But let's imagine, for a moment, a different kind of box. One where actions outside the box 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 the ratios and outputs)).
@ -67,13 +62,13 @@ Side effects introduce unpredictability into our programming relationships. Wher
We call a function that is unpredictable, or has side effects, "impure", and one that isn't - "pure".
It was obvious how we could cause unpredictability by including randomness. On the left we have two impure functions.
It was obvious how we could cause unpredictability by including randomness. But here's another example, on 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.
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 state 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.
@ -106,9 +101,9 @@ def make_birthday_cards(people):
return cards
```
But this is getting annoying; what about Christmas, Thanksgiving, Easter, or another life event such as a wedding? Making this list of new cards and going through each person every single time is getting really tedious.
But this is getting annoying; what about Christmas, Thanksgiving, Easter, or another life event such as a wedding? Making this function to make a list of new cards, going through each person every single time is getting really tedious.
What if we create a bunch of black boxes that take a person and create them a card, specifically. Then we create a black box that takes a list of people and another black box and creates a new card for each person?
To help, we create a bunch of black boxes that take a person and create them a card, specifically. Then we create a black box that takes a list of people and another black box and creates a new card for each person?
```python
def valentine_letter(person):
@ -133,14 +128,16 @@ people = [{"name": "Joseph", birthday: new Date()}, {"name": "DeeDee", birthday:
buildCards(people, birthdayCard)
```
The ability 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
===
After exploring the simple yet profound beauty of using black boxes in black boxes, our journey into the functional programming romance takes an intriguing turn. What's better than one black box the uses a black box? A black box that creates more black boxes.
After exploring the simple yet profound beauty of higher order black boxes, our journey into the functional programming romance takes an intriguing turn. What's better than one black box? A black box that creates more black boxes.
All life on Earth contains instructions in the form of DNA. During mitosis, special mechanisms in our cells read the instructions and create new instructions to give to another cell.
Very similarly, we can give our black boxes DNA from parents to reproduce and create new child black boxes. But in our world of black boxes, we call these "closures".
Very similarly, we can give our black boxes DNA from parents to reproduce and create new child black boxes. But in our world of black boxes, we refer to this DNA as "closures".
```
def cardGeneratorFor(person, type):
@ -224,7 +221,9 @@ cards = buildCards(people, valentineMaker)
This function actually has a small side effect - though it's contained entirely within the function - when we append to the cards list. If we were to go about living a side effect free life, that means we can't change _anything_.
So how do we murder an impostor? With copies and recursion.
Loops inherently produce side effects (mutation of the loop variable), so we need to eliminate them.
So how do we sus out an impostor? With copies and recursion.
```
def build_cards(people, card_maker):

View File

@ -1,8 +1,10 @@
import { Node, Txt, makeScene2D } from "@motion-canvas/2d";
import { Layout, Txt, makeScene2D } from "@motion-canvas/2d";
import {
Direction,
beginSlide,
createRef,
range,
all,
makeRef,
slideTransition,
} from "@motion-canvas/core";
@ -31,23 +33,27 @@ const hungryValentine = `(
);
const foodNames = Array.from(Object.keys(foods));
const shouldChooseRandom = Math.random() > 0.4; // side effect
const shouldChooseRandom = Math.random() > 0.7; // side effect
return shouldChooseRandom
? foodNames[Math.floor(Math.random() * foodNames.length)]
: bestFood;
};`;
export default makeScene2D(function* (view) {
const functionBox = createRef<FunctionBox>();
const functionBoxes: FunctionBox[] = [];
view.add(
<Layout direction={"column"} gap={20} layout>
{range(3).map((i) => (
<FunctionBox
arity={4}
idlingText={"😴"}
workingText={"😋💭"}
source={hungryValentine}
ref={functionBox}
/>,
ref={makeRef(functionBoxes, i)}
/>
))}
</Layout>,
);
yield* slideTransition(Direction.Right);
@ -59,13 +65,14 @@ export default makeScene2D(function* (view) {
for (const [[a, b, c, d], i] of [
[0.7, 0.1, 0.4, 0.1],
[0.7, 0.1, 0.4, 0.1],
[0.7, 0.1, 0.4, 0.1],
[0.7, 0.1, 0.4, 0.1],
].map((x, i) => [x, i]) as [[number, number, number, number], number][]) {
const inputId = "(" + [a, b, c, d, i].join(",") + ")";
yield* functionBox().reset(0.5);
yield* functionBox().setInputs(
yield* all(...functionBoxes.map((box) => box.reset(0.5)));
yield* all(
...functionBoxes.map((box) =>
box.setInputs(
[a, b, c, d].map((ratio, i) => ({
val: ratio,
node: (
@ -87,22 +94,27 @@ export default makeScene2D(function* (view) {
),
})),
0.5,
),
),
);
yield* beginSlide("Add Inputs " + inputId);
yield* all(...functionBoxes.map((box) => box.propogateInput(0.5)));
yield* functionBox().propogateInput(0.5);
yield* beginSlide("Propogate Inputs " + inputId);
yield* functionBox().propogateOutput(0.5);
yield* all(...functionBoxes.map((box) => box.propogateOutput(0.5)));
yield* beginSlide("Propogate Outputs of " + inputId);
}
yield* functionBox().reset(0.5);
yield* all(...functionBoxes.map((box) => box.reset(0.5)));
yield* functionBox().showCode(0.85);
functionBoxes.slice(1).map((box) => box.remove());
const [root] = functionBoxes;
yield* root.showCode(0.85);
yield* beginSlide("Show Code");
yield* functionBox().hideCode(0.85);
yield* root.hideCode(0.85);
yield* beginSlide("Hide Code");
});

View File

@ -14,6 +14,6 @@ export const scenes = [
//flirtingwithfunctions,
//doctor,
//first_box,
//hungry_partner,
hungry_partner,
pure_functions,
];

View File

@ -26,8 +26,9 @@ const impureFib = (n: number) => {
impureFib;`;
const impureFactFunction = `const impureFact = (n: number): number => {
while (cache.length <= n)
cache.push(cache.length *
cache[cache.length - 1]);
cache.push(
cache.length * cache[cache.length - 1]
);
return cache[n];
};
impureFact;`;