Skip to content

Latest commit

 

History

History
170 lines (96 loc) · 3.42 KB

lesson9-continuations.md

File metadata and controls

170 lines (96 loc) · 3.42 KB

Part 9

Effects and things happening

So far we've looked at a couple of things:

  • Option and Either which are both functors and monads

  • They've helped us express stuff that goes wrong, as life does

  • Lots of different monoids for strings and things

  • These have helped us formalise the smashing together of data

Recap:

All of the abstractions we've looked at so far have a few things in common:

  • They are pure

  • They are synchronous

  • But surely you must find yourself asking...

  • "That's all great, but where is the business value hiding?"

Bombshell:

  • Today we're going to hold onto purity like our life depends on it

  • ...but throw synchronous out of the window and straight through the sunroof of some idiot's passing sportscar

But first, as ever...

...a meandering distraction.

So far, we've not been concerned about time. Pure functions are handy like that. They simplify down like maths equations.

  • a = (6 * 3) + (4 + 2)

  • a = 18 + (4 + 2)

  • a = 18 + 6

  • a = 24

  • OK

The same but with functions

If we look at the above as a bunch of functions though, it's more apparent there is some sort of ordering to how things are calculated.

a = add(multiply(6,3), add(4, 2))

  • The outer add function adds numbers, not functions, therefore, it can't do anything.

  • But multiply deals with numbers, and it has those, so let's do that:

a = add(18, add(4,2))

  • We still can't add 18 to a function, but we can calculate the inner add:

a = add(18, 6)

  • And now the outer function is ready to go brrrrrrrrrrr:

a = 24

OK

Let's look at the functions we've been using a lot of recently:

map :: (A -> B) -> Option A -> Option B
  • (brief recap)
const map = <A, B>(f: (a: A) => B, a: Option<A>): Option<B> =>
  a.type === 'Some' ? some(f(a.value)) : none()
  • Ordering doesn't really matter here, all the values are ready to go

What about?

Let's imagine a fictional type Async<A>.

  • Think of it like a Promise<A>, ie something that will give me an A at some point

  • How does map work ordering wise there?

map :: (A -> B) -> Async A -> Async B
  • What's going to happen, roughly, step by step?

  • .

  • ..

  • ...

OK, now onto our friend Bind

What about bind?

bind :: (A -> Async B) -> Async A -> Async B`
  • What's going to happen? How long is it going to take?

  • .

  • ..

  • ...

What if there was a third way?

Meet our new buddy ap. Conceptually, he lives somewhere between map and bind.

  • He works on a bunch of our old friends:
ap :: Option (A -> B) -> Option A -> Option B
ap :: Either E (A -> B) -> Either E A -> Either E B
  • He can be quite helpful there, but not particularly interesting.

  • However...

  • Today though, we'll look at him with our new Async friend:

Let's think about what's going to need to happen here:

ap :: Async (A -> B) -> Async A -> Async B
  • We wait for an A -> B function from our first Async

  • We also wait for an A value from our second one.

  • Then we smash them together.

  • What's different and useful about this?

  • What if each of our Asyncs were doing long slow API calls?

Continuation

Today we're going to build a thing called Continuation (in some places it's called Cont)

It's better than a callback, worse than a Promise.

We can improve him in future though.