A function const id = x => x becomes a continuation passing style function in Javascript as soon as you add a function argument and call it with the result value in tail position: const id_ = x => k => k(x). The actual continuation emerges when you apply the CPS function: id_(2) yields const id2 = k => k(2), the continuation.
You can compose normal functions with const comp = f => g => x => f(g(x)) and then comp(id) (id). But can you compose continuations like id2 as well?
// doesn't work, cont2 returns a value but cont expects a fun const comp_ = cont => cont2 => k => cont(cont2(k)); // works but x is awkwardly discarded const comp_ = cont => cont2 => k => cont2(x => cont(y => k(y)); Unfortunately, no. There is no specialized comp_ operator for id2 to compose two continuations in a general way. But there is a way to compose the CPS version id_ with its continuation id2:
const comp_ = cont => cps => k => cont(x => cps(x) (k)); const f = comp_(id2) (id_); f(id); // yields 2 since we are only composing identity comp_ a.k.a. chain/bind is one part of the monad interface. The second one is const of = x => k => k(x), which simply puts a normal value into the monad context:
const chain = cont => cps => k => cont(x => cps(x) (k)); const of = x => k => k(x); const f = chain(of(3)) (id_); f(id); // yields 3 So not just the continuation monad but monads of all types are just the most general way to compose/chain expressions of those types using continuations under the hood. Please note that monads are a very generalized and thus subtle concept. Stare at it long enough, play with it once in a while and you'll eventually get it.
Top comments (0)