Skip to content

Commit a0318cf

Browse files
committed
Freshen up slides
1 parent 8cfd60d commit a0318cf

File tree

5 files changed

+268
-305
lines changed

5 files changed

+268
-305
lines changed

intro.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Hello.
22

3-
### Functional programming is ~~exciting~~ boring
3+
## __Functional programming is exciting__
44

5-
### ~~Functional~~ imperative programming is difficult
5+
## Functional programming is boring
66

7-
### Functional programming is **tediously predictable**
7+
## __Functional programming is difficult__
8+
9+
## Imperative programming is difficult
10+
11+
## Functional programming is **tediously predictable**
812

913
## What's the big idea then?
1014

slides/complexity.md

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Cardinality
2+
3+
## Measuring complexity
4+
5+
- Reducing complexity is good, and so it's helpful to have a way of measuring
6+
it.
7+
8+
- Look at this simple type:
9+
10+
```typescript
11+
type ManyOptions = {
12+
type: 'electricity' | 'gas'
13+
eco7?: boolean
14+
}
15+
```
16+
17+
- How many options could there be above?
18+
19+
- What about now?
20+
21+
```typescript
22+
type SlightlyLessOptions = {
23+
type: 'electricity',
24+
eco7: boolean
25+
} | {
26+
type: 'gas'
27+
}
28+
```
29+
30+
- A small change reduces the number of options, and thus the number of code
31+
paths needed to deal with it.
32+
33+
- Although it's trivial now, as a data type grows it becomes more significant.
34+
35+
```typescript
36+
type ContrivedTariff = {
37+
type: 'electricity' | 'gas',
38+
eco7?: boolean
39+
elecReading?: number
40+
gasReading?: number
41+
}
42+
```
43+
44+
## How do we measure it?
45+
46+
This measure of how many possible values exist in a type is called *cardinality*.
47+
48+
- It is defined by the first result in a Google search I just did as:
49+
50+
`the number of elements in a set or other grouping, as a property of that grouping.`
51+
52+
- `Boolean` can be `true` or `false`
53+
54+
- so...?
55+
56+
- Yes, indeed, `2`.
57+
58+
- `type TrafficLights = 'Red' | 'Green' | 'Blue'` ..?
59+
60+
- of course, `4`.
61+
62+
- I mean `3`. Lolle.
63+
64+
- The cardinality of `string` or `number` is very large indeed
65+
66+
- How does this relate to our new friends `Either` and `Maybe`?
67+
68+
## Algebraic Data Types
69+
70+
- So `Maybe` and `Either` are both examples of `Algebraic Data Types`
71+
72+
- More accurately, `sum types`
73+
74+
- (The other kind are `product types`, we'll come to those...)
75+
76+
## Maybe
77+
78+
- `Maybe A` is a `sum type` because it's *cardinality* is
79+
80+
- the sum of `whatever the cardinality of A is` and `1`
81+
82+
- So `A` + `1`, kinda.
83+
84+
- (The `1` is to represent `Nothing`)
85+
86+
- The type `Maybe<boolean>` could have values of either
87+
88+
- `Just(true)`
89+
90+
- `Just(false)`
91+
92+
- `Nothing`
93+
94+
- So, `3`.
95+
96+
## Either
97+
98+
- `Either E A` is also a sum type, but it's `cardinality` is
99+
100+
- the sum of `the cardinality of E` and `the cardinality of A`
101+
102+
- so `E + A`, sort of (if you squint)
103+
104+
- So `Either<boolean, boolean>` would be `2` + `2` = `4`
105+
106+
- or `Either<TrafficLights, boolean>` would be `3` + `2` = `5`.
107+
108+
## This is complex
109+
110+
But how does it relate to complexity?
111+
112+
- Bare with me - I swear we're getting to a breakthrough
113+
114+
## Product types
115+
116+
- `Product types` are the other kind of `Algebraic Data Type` (`ADT`)
117+
118+
- They are way more boring tbh.
119+
120+
- Most Typescript interfaces are `Product types`
121+
```typescript
122+
interface Person {
123+
name: string
124+
age: number
125+
}
126+
```
127+
128+
- When it comes to data modelling, they are the probably the tool we reach for
129+
first.
130+
131+
- (And why wouldn't we? They are broadly supported and it's considered idiomatic
132+
to do so.)
133+
134+
- (And I'm not writing a thinkpiece named __Javascript Objects Considered Harmful__ or anything)
135+
136+
- (yet)
137+
138+
## Anyway
139+
140+
- Whilst `sum types` describe `this` *OR* `that`.
141+
142+
- `Product types` describe `this` *AND* `that`.
143+
144+
- So, a `Person` interface is just a nice way of carrying around a `string` *AND* a `number`
145+
146+
## Tuple
147+
148+
- A good example of how these things are actually very similar is `Tuple`.
149+
150+
- A very simple simple product type is `Tuple A B`
151+
152+
- We could represent it like this:
153+
```typescript
154+
type Tuple<A,B> = { type: "Tuple", a: A, b: B }
155+
```
156+
157+
- It is the *dual* of `Either`...
158+
159+
- `Either<A,B>` is `A` *+* `B`.
160+
161+
- `Tuple<A,B>` is `A` *x* `B`.
162+
163+
- A `Tuple<string,number>` could represent `Person` interface from before as
164+
it's their `name` *AND* `age`.
165+
166+
- Whilst `Either<string,number>` could be used to describe a person's `name` *OR*
167+
`age`.
168+
169+
- (I'm not sure why you would do this, admittedly)
170+
171+
- So, knowing that the *cardinality* of `Either<TrafficLights, boolean>` is `5`
172+
173+
- What is *cardinality* of `Tuple<TrafficLights, Boolean>`...?
174+
175+
- .
176+
177+
- ..
178+
179+
- ...
180+
181+
- `3` x `2` = `6`
182+
183+
## Complexity, to recap
184+
185+
- We calculate the cardinality of a `sum type` with `+`
186+
187+
- But for `product types` we use `x`
188+
189+
- You can imagine which ones end up bigger
190+
191+
- Adding another `boolean` multipies the options by `2`.
192+
193+
- And adding an `optional boolean` multiplies the options by `3`.
194+
195+
- So wherever you find yourself adding more rows to a type, think
196+
197+
- Will this __REALLY__ always be there?
198+
199+
- Or can I make it a `sum` instead?
200+
201+
## Extra task time
202+
203+
- Given a constructor for making `Tuple` types:
204+
```typescript
205+
const tuple = <A,B>(a: A, b: B): Tuple<A,B> =>
206+
({ type: "Tuple", a, b })
207+
208+
tuple("Horse", 100)
209+
// { type: "Tuple", a: "Horse", b: 100 })
210+
```
211+
212+
- ...can we implement some of the functions we made for `Either` for `Tuple`?
213+
214+
- `map :: (B -> D) -> Tuple A B -> Tuple A D`
215+
216+
- `leftMap :: (A -> C) -> Tuple A B -> Tuple C B`
217+
218+
- `bimap :: (A -> C) -> (B -> D) -> Tuple A B -> Tuple B D`
219+
220+
- `match :: (A -> B -> C) -> Tuple A B -> C`
221+
222+
- Why is implementing `join` or `bind` difficult?
223+

slides/currying.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Currying
2+
3+
## A note on currying
4+
5+
Often in functional languages (or indeed, in libraries like `Ramda` or `fp-ts`)
6+
our functions are `curried`
7+
8+
This means they are split into single arity functions that each return the rest
9+
of the function.
10+
11+
The regular example is this:
12+
13+
```typescript
14+
const add = (a,b) => a + b
15+
```
16+
17+
- becoming this...
18+
19+
```typescript
20+
const addCurried = a => b => a + b
21+
```
22+
23+
- which allows
24+
25+
```typescript
26+
const add2 = addCurried(2)
27+
28+
add2(1) // 3
29+
```
30+
31+
- This is used a lot so that functions like `map` and `bind` can be used
32+
point-free.
33+
34+
- It does make things a lot more dense though
35+

slides/lesson1-maybe.md

+2-78
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ const tidyHorseName = (horse: Horse): Horse => {
5858
};
5959
```
6060

61-
- But wait, we're not dealing with `horse`
61+
- But wait, we're not dealing with `Horse`
6262

63-
- We're dealing with `horse | undefined`
63+
- We're dealing with `Horse | undefined`
6464

6565
- So we either make our horse tidying function more accomodating...
6666

@@ -348,79 +348,3 @@ fromMissing(undefined)
348348
349349
- Down to you...
350350
351-
## Answers
352-
353-
- These are not the only answers, but some answers
354-
355-
- map
356-
357-
`map :: (A -> B) -> Maybe A -> Maybe B`
358-
359-
```typescript
360-
const map = (func: (a: A) => B, maybe: Maybe<A>): Maybe<B> =>
361-
maybe.type === "Just" ? { type: "Just", value: func(maybe.value) } : maybe;
362-
```
363-
364-
- orElse
365-
366-
`orElse :: (A -> B) -> B -> Maybe A -> Maybe B`
367-
368-
```typescript
369-
const orElse = (func: (a: A) => B, def: B, maybe: Maybe<A>): Maybe<B> =>
370-
maybe.type === "Just" ? func(maybe.value) : def
371-
```
372-
373-
- join
374-
375-
`join :: Maybe (Maybe A) -> Maybe A`
376-
377-
```typescript
378-
const join = (value: Maybe<Maybe<A>>): Maybe<A> =>
379-
value.type === 'Just' ? value.value : nothing()
380-
```
381-
382-
- bind
383-
384-
`bind :: (A -> Maybe B) -> Maybe A -> Maybe B`
385-
386-
```typescript
387-
const bind = (func: (a: A) => Maybe B, value: Maybe<A>): Maybe<B> =>
388-
value.type === 'Just' ? func(value.value) : nothing()
389-
```
390-
391-
## A note on currying
392-
393-
Often in functional languages (or indeed, in libraries like `Ramda` or `fp-ts`)
394-
our functions are `curried`
395-
396-
This means they are split into single arity functions that each return the rest
397-
of the function.
398-
399-
The regular example is this:
400-
401-
```typescript
402-
const add = (a,b) => a + b
403-
```
404-
405-
- becoming this...
406-
407-
```typescript
408-
const addCurried = a => b => a + b
409-
```
410-
411-
- which allows
412-
413-
```typescript
414-
const add2 = addCurried(2)
415-
416-
add2(1) // 3
417-
```
418-
419-
- This is used a lot so that functions like `map` and `bind` can be used
420-
point-free.
421-
422-
- It does make things a lot more dense though
423-
424-
## One last thing
425-
426-
- https://egghead.io/lessons/javascript-you-ve-been-using-monads

0 commit comments

Comments
 (0)