DOUGLAS CROCKFORD: So I'm going to show
you some code today.
Ordinarily, I don't like talks with a lot of code in them,
because I think they're tedious and boring.
And this talk promises to be no exception.
But code is the story.
And so it's not possible to tell this otherwise.
So the topic this morning is monads.
Monads, what are monads?
Monads are this strange, mysterious, weird, but
powerful, expressive pattern that we can use for doing
programming.
And they come with a curse.
The monadic curse is that once someone learns what monads are
and how to use them, they lose the ability to explain it to
other people.
There's lots of evidence of this on the web.
Go and search for monads tutorials, burritos, any of
those things, and you're going to find a lot of really
confusing material.
So today I'm going to attempt to break that curse, and show
you monads for what they actually are.
So we're going to start with functional programming.
If you can't do functional programming, then none of the
rest of this is going to make sense.
But I'm assuming you're all professionals, and this should
not be difficult material.
So there are two senses of the term functional programming.
One of them simply means to program with functions, so
we'll look at that first.
Functions enter mainstream programming with Fortran II.
This is a Fortran II function.
At that time, lowercase hadn't been invented yet, so
everything was in uppercase.
But it looks quite a lot like a modern function.
It starts with the word function.
It has the name of the function, and parameters
wrapped in parentheses, separated by commas--
really conventional stuff.
So it's just a subroutine that had the
ability to return a value.
And it returned that value in a slightly strange way, using
assignment statement, which would assign a value to the
name of the function.
And then the return statement would
deliver that to the caller.
That has been changed since then, and now everybody has a
return statement that takes a value, and that works better.
Or in expression languages, the last expression evaluated
by a function is the implied return value.
But what we called functional programming only becomes
interesting when we have functions
as first class objects.
So we can take a function and pass it as a parameter, or
store it in any variable, or stick it in
the field in a record.
That's when it becomes interesting.
Then we can have higher order functions, in which you have
functions which operate on other functions as arguments.
And this all became really good stuff with the
invention of Scheme.
In Scheme we have what's will closure, which means that any
function has access to the variables
in the outer function.
And it turns out that was an enormous breakthrough.
And that is now finding its way into mainstream languages.
Anyone have any idea which was the first mainstream language
to have this feature?
It was JavaScript.
That's right.
JavaScript is leading the way.
So the other sense of functional programming is
sometimes called pure functional programming.
And it means functions are mathematical functions, which
is quite different than
subroutines that return arguments.
Because a subroutine is allowed to do mutation.
And in a purely mathematical function, that doesn't happen.
A function with some input is always going to
have the same output.
And the argument in favor of that style of programming is
it makes programs a lot easier to reason about, because you
don't have bugs that will occur as a result of side
effects of something else happening.
If something works, it's guaranteed to work that way
correctly until the end of time.
And that could be hugely beneficial.
But there are problems that come with that.
So you could think of mathematical functions as
being maps.
It will simply take some parameter or parameters, and
map them to some value.
And that mapping is constant, and so it
always works that way.
And so it's easy to predict.
So whether functions are implemented as computation or
as association is just an optimization trick.
All functions should work exactly the
same way, either time.
So the difference is like the difference between memoization
and caching.
Caching is a deal with the devil, right?
We have something, which is likely to be wrong but is
sometimes right, and we don't know when it transitions from
being right and wrong.
With memoization, that never occurs.
Once it's memoized it's right and will always be right.
We can take any ordinary programming language and turn
it into a purely functional programming language by
deleting stuff.
So we can remove everything from the language which could
have side effects.
So we could remove the assignment statement.
We can remove loops, and use recursion instead if we need
repetition.
We can freeze all array literals an object literals so
that once minted, they cannot be modified.
In languages like JavaScript, it means removing Date.
Because every time you call Date, it
returns a different value.
That's mathematically absurd.
Every time you call a function, it should return the
same thing.
Same with random.
Every time you call random, you hope to
get a different value.
But that's that doesn't make sense mathematically.
So we want to remove that.
So remove all those things from our languages, then we'll
have purely functional languages, and we'll also find
we're not going to be able to get anything done anymore.
Because most of our programs are not doing pure
computation.
They're interacting with the world.
And the world is constantly changing.
And if our programs can't change with them, then they
become brittle and ineffective.
In the real world, everything changes.
And immutability makes it hard to work in the real world.
Now there are pure functional programming languages like ML,
and like Haskell is a better example.
And Haskell is a brilliant language.
And they were doing interesting computations with
it, and then there was the idea, let's try to do
practical stuff in it.
And then suddenly it gets really, really hard.
That kind of hard is sometimes called impossible, because you
can't have any side effects.
You can't do I/O. How do you interact with things without
being able to do I/O, without being able to mutate?
So they discovered a trick.
There was a loophole in the function contract.
And that loophole is that a function can take a function
as a parameter.
And once it does that, every time a function is called with
a function, every function is going to be different, because
every function is a unique thing, which is closed over
the thing that created it.
And so it sort of gives us a way to escape from the
side-effect-free thing.
You just need to start thinking about how you compose
functions in such a way that you have the illusion of
having mutability without actually mutating anything.
So the Haskell community had reason to adopt something
called the I/O monad, because it gave them the ability to
act as though the language had I/O, even though it didn't.
And so as they're calling things, they can be assembling
state, and that state kind of follows forward in the
computation.
And it kind of works.
It's like, hurray.
It could be used for practical programming, except
it's kind of hard.
And it turns out that you want mutation, because that is how
the world works.
And so the I/O monad is a solution to a problem you
should never have.
But it turns out there are lots of other monads, and so
they're still worth taking a look at.
There's some who will say, in order to understand monads,
you first have to learn Haskell, and you have to learn
Category Theory.
If you don't know these things, there's just the no
way to start.
You can't learn monads.
I think that is true in exactly the same way that in
order to understand burritos, you must first learn Spanish.
And they're true in the same way in that neither is true.
It turns out you can do a lot of stuff with burritos without
knowing any Spanish.
You can order them.
You can eat them, and enjoy them.
You can even learn to make them.
You can even learn to invent new kinds of burritos, which
you and your friends can enjoy.
And you can do that without learning any Spanish.
I'm not saying you shouldn't learn Spanish.
There are lots of good reasons to learn Spanish.
You can learn a lot more about Mexican cuisine, for example.
And that will allow you to make burritos and other
things, which are more authentic, and
perhaps even better.
It'll allow you to have interactions with some
wonderful people you would never interact with otherwise.
And if you're one of the job creators, it gives you an
opportunity to talk directly to the people who are actually
doing your work for you.
That's a good thing, right?
So in the same way, it's good to learn Haskell.
Haskell has a lot of good stuff in it.
It can teach you a lot.
It's a good language to learn.
It's just not necessary to learn Haskell in order to
understand monads.
Some people will disagree with me, and say no, you have to
start with Haskell.
And I say no.
If you have the chicharrones, you can learn
monads without Haskell.
Some people will say, well you at least have to start with
the types, that you need a really strongly typed
language, or a super strongly typed language in order to
manage monads.
You have to understand this before we begin.
And I'm going to tell you, no, that's
actually not true, either.
Haskell has a wonderful type system.
And it does a lot of type inference, so that you can
under-specify what the program does, and it will try to
figure out all the types.
But it doesn't always go right.
And so if it is trying to solve your program, and it
finds an inconsistency, it stops.
And you get this completely opaque message, which is
indicating that it found an inconsistency in a place which
is probably miles away from where the error actually is.
And so getting that stuff to work and compile
can be really hard.
And once it's done, there's folklore which says, having
gone through that ringer, you're guaranteed your program
is going to be error free.
And it turns out it's not, that there are subtle errors
that happen in Haskell, as happen in all other languages.
And the type system actually gives you no leverage in
dealing with that stuff.
Stuff gets complicated, and when there's complexity,
things go wrong.
And that happens in all languages.
It turns out that it's easier to reason about monads if you
don't have to deal with the type stuff.
You don't actually need to understand what that is in
order to build a monad.
Now there's some who will say, no, that's not true.
You don't dare go that way otherwise.
But I say, my friends, if you have the huevos, you can.
So what do you say we sock up and look at some monads?
It turns out, the language you need to learn first is
JavaScript.
Because it has the higher order function
stuff that we need.
And it doesn't have any the type stuff to get in your way.
So you can just think about what's going on.
So what we have here is a story of three functions.
We have a function called unit that takes a value
and returns a monad.
We have a function called bind, which takes a monad and
a function that takes a value that returns a monad.
That's it.
So all three of these functions return
monads, and that's it.
That's monads.
Thank you very much.
So you're probably wondering, still, what is a monad.
A monad is an object in this case.
It could be something else.
But generally it's an object.
So if you know anything about JavaScript, you're looking at
the unit function, you're going, wait, unit is a
function that takes a value and returns an object, so it
must be a constructor.
And yeah, right., that's exactly right.
So unit is constructor.
So nothing magical there.
So all the magic must be in the bind function.
So that's it.
And there's not a lot of magic.
So there are three axioms that you have to hold in order to
be a monad.
The first to describe the relation between bind and
unit, which is basically that unit creates a monad that
represents some value, and the bind function allows another
function to have access to that value.
The interesting axiom is the third one, which tells us how
we can do composition on the bind method--
that we can have nested bind methods, and that does the
same thing as calling bind with a
function that calls bind.
That's it.
That is monads.
Now we can make it easier to deal with these monads by
converting it from functional notation
into methodical notation.
That's a really easy thing to do in JavaScript.
Everybody does that all the time.
You need to understand the mapping between functions and
methods, and once you can do that, then we can very easily
transform the way we invoke the blind method.
Instead of saying bind passing a monad, we'll call the
monad's bind method.
It's just an easier way to do that.
Some languages, say Common Lisp, you would recognize that
there are lots of different possible varieties of monads
that you might want to implement, but they all have
the same basic pattern.
So you'd want to implement some kind of macro to make it
easier for defining all those different kinds of monads.
JavaScript unfortunately does not have macros.
But it does have functions, and so we can create a special
kind of function called a macroid, which acts like a
macro, which helps us to do that kind of
thing that macros do.
So this is one of those macroids.
I want to say something about the coloring.
You've all seen syntax coloring, right?
That's something we put in our text editors to make it easier
for kindergartners to do programming.
Because each of the elements of the language is a different
happy bright color, and so it's easy to recognize, oh
that's a variable, and that's a string, and so on.
I don't get a lot of value out of that because I am more of a
grown up, and I'm a professional programmer.
And I really don't need the colors to figure out what's a
variable and what's a comment.
But when I'm doing functional programming, I would like to
have color help me deal with the nesting of functions, and
deal with the closure.
So I wish someone would make a text editor for
me that does this.
So I want all my global-level stuff to be white.
All the top-level functions, I want them to be green.
The functions defined inside of those would be yellow.
The ones inside of those would be blue, and so on.
But the color of a variable is the color in which it was
defined, and that allows me to see how things close.
It gives me a view of the visibility of the variables
and their life expectancy, and so on.
And that turns out to be really useful stuff.
So I'd really like to have this kind of colorization.
And I'm going to be using this sort of colorization through
the rest of this talk.
So we've got our macroid.
And we're going to use it to define a monad.
And we're going to start with the identity monad.
So the identity monad will build the identity
constructor.
And we'll call the identity constructor, passing it the
"Hello world" string.
And then when we call monad.bind, passing alert, the
alert function as its method, we'll get the
"Hello world" thing.
So this is the simplest slightly useful monad, the
identity monad.
Let's look at the axioms again, using the methodical
notation that we just came up with.
We previously looked at it functionally.
Now we look at it methodically.
And I think it actually makes more sense in this notation.
I think it's easier to see what the relationship between
unit and bind is.
But even better is the thing that happens in composition.
We now have this thing where we've got a monad.
And we call bind.
And it returns another monad.
And we can call bind again.
This is a much easier composition pattern than the
other one, in which we had bind nested inside of bind,
because with the nesting, you have to read the expressions
from the inside out.
And that's a hard thing for us to do.
But in the methodical form, we can read it
from left to right.
And so composition is a lot easier.
I can just keep tacking things on, and the thing keeps
getting longer, and more interesting, more complex.
Any of you who have ever done any Ajax programming might
notice there's something about this pattern that's familiar.
I've got an object.
I call a method on it.
Then I call another method on the result.
Where have I seen that before?
It's the Ajax monad.
All of the Ajax libraries do this--
JQuery, YUI, everybody.
We've been doing this for years.
It turns out we've been doing monads all along.
This is an example of something I did in 2001.
The Interstate library was my third JavaScript library.
The first one was just something to help me manage
the differences between Netscape 4 and IE 4, which
were horrendous.
And after I wrote that, I looked at what sort of
patterns we were using in using it, and then trying to
figure out a way to incorporate more of that into
the library to make it easier to use.
And this is my third iteration.
And in this one I realized that if I have an object which
wraps a DOM node, in this case, a text form node, and if
that object, that monad keeps returning itself, then I can
cascade all of these other things on it.
And it becomes really expressive.
And lots of other people figured this
trick out as well.
And so this is now standard equipment in Ajax libraries.
In 2007, I developed a system called ADsafe which was
intended to make the web safe for doing online advertising.
And it took the same idea of taking a node and wrapping it
in a monadic object, but also added a security
dimension to it.
So it would guarantee that there was no way that the node
could be extracted from the object.
So that meant we could give one of these ADsafe nodes to a
piece of untrusted code, for example, an advertisement, and
be confident that it could not break the containment, that it
was only able to do with that node what we intended it to be
able to do with that node, and nothing else.
It couldn't use it to traverse the rest of the document.
It couldn't use it to get to the network.
It couldn't use it to steal our cookies.
It couldn't do any of those things.
All it could do was display an ad in that window.
And ADsafe worked.
And it used the same monadic pattern.
So let's improve our macroid to allow us to do Ajax stuff.
So we've already seen we can take an object and
call a bind on it.
But what we really want to be able to do is
call a method on it.
Also, we want to be able to have methods pass some
variable number of parameters, as well.
So we'll expand our bind method to now take an optional
second parameter, which is an array of the arguments that we
want to get to the method.
And we'll extend our macroid by first creating a prototype
object, which will be an object which inherits nothing.
This is where we're going to keep the methods of the monad.
We can use object.create of null to make that for us.
It makes an object that inherits nothing.
This is a great new feature that came in the ES5.
And then when we create our monad, we will have it inherit
from that prototype object.
So anything that goes into the prototype object will be
inherited by the monads that we make.
Then we'll modify the blind method to take the second
argument, which is the set of arguments that we want to pass
into the method.
And unfortunately, because of a profound stupidity in the
way JavaScript was designed, we have to manipulate the
arguments object.
And that's really hard, because it
is not a real object.
And so the things you have to do to it are horrible.
Fortunately, ES6, the next edition of the language, will
probably have this dot dot dot operator, which happens to do
exactly the right thing.
This is going to be my second favorite feature in ES6 if it
ever comes out.
So I'm looking forward to that.
Because it took those three extremely ugly lines, and
turned it into one very neat line, which obviously does
what it does.
We're then going to create a unit method on the
constructor, which will allow us to add additional methods
to the prototype.
It simply takes its arguments, and assigns them to the
prototype, so that's pretty easy.
And it also returns unit, so that we can then call dot
method dot method dot method on the constructor.
So it's monadic in that dimension, as well.
But we can do even better than that.
It assumed that the functions that get called to method
understand about monads.
But in some cases we want to be able to wrap functions that
know nothing about monads, but have them work
in the monadic context.
So we're going to add another method to the constructor,
called lift.
And lift will take an ordinary function and
add it to the prototype.
But it will wrap that function in another function, which
will call unit and bind, as suggested in
the first two axioms.
So that it allows that function to act as though it
knew about monads, even though it didn't.
So it'll call bind for us, and it will then wrap it's result
in a monad if it needs to.
So this makes things a lot easier.
So let's use this one.
We're going to call our macroid again to
make our Ajax monad.
And we're going to use lift to turn alert
into a method on it.
So we could change the name here.
But we're going to keep the name the same.
We're going to take the alert function, and use it as the
alert method.
So now I can call the Ajax constructor to make my monad.
And the monad now has an alert method.
And if I call it, it'll say, "Hello world." Hooray.
It turns out we've been doing this for years.
We just didn't know it.
Ajax has always been monadic.
One of the difficulties we have in some of our modern
languages is the problem with null.
Null as the thing that represents a
value that is not there.
And if you try to do something to null, generally something
bad will happen.
Sometimes it seems that Java was optimized for the
generation of null pointer exceptions.
So you end up having--
the null pointer exception doesn't actually ever tell you
anything, except that there was a null that you didn't
check there to avoid.
And so your code tends to get filled with lots of, if null,
don't do that, if null, don't do that.
Which is just a waste of time.
It's completely unproductive.
We knew we didn't want to do that.
We shouldn't have to say so every time we touch a variable
that might want to null.
So there's a thing called the maybe monad.
The maybe monad takes null pointer exceptions and simply
removes them from your model, so you never have to worry
about them anymore.
It's similar to the weight that NaN works.
A long time ago, in Fortran and another languages, if you
ever accidentally divided something by zero, your
program would stop.
Exception, thing crashes, cores, done, stops.
So as a result, you had to write in front of every
division, but if we're dividing by zero,
then don't do it.
You never intended to have it happen, but you had to guard
against it all the time.
So we now have NaN.
And NaN represents Not a Number.
It's sometimes the result of dividing by zero.
And so if we divide by zero, we get NaN instead.
And the program keeps going.
At the end you can ask, by the way, is the answer NaN.
No, OK, something happened.
We can ignore the result.
So that's much nicer than having to put guards around
every operator to make sure that
nothing's going to go wrong.
The maybe monad allows us to do a similar thing with
pointers or references, so we don't have to
worry about that anymore.
Those errors don't happen.
So we're going to modify our macroid in order to be able to
deal with maybe monads.
So we're going to add a parameter to the macro, which
takes a modifier function.
And that modifier function will allow us to intercept
things that we're constructing.
So the unit method, as part of its doing work, will look to
see if the modifier function is present.
And if so, it will call it, passing the
monad and the value.
And that will allow that function that we pass in to do
something with the thing that we're making.
One way we can do that is we can use the macroid to make a
maybe monad by passing in this function, which will look at
the value, and see if the value is null or undefined.
And if it, then we go, this is going to be a null monad.
And it's going to have this amazing property, in that
we're going to change its bind method to do nothing.
It will simply return the monad.
So it turns it into an identity function, and crashes
don't occur.
So now we can make our maybe monad--
this case, we'll make a null one--
and if I call bind on alert, nothing happens.
It's great.
So if you incorporate this kind of stuff into your
system, you never again have to worry about
null pointer errors.
It's just amazing.
They just go away.
Bind will prevent it eve from getting called, and everything
works right, which is nice.
It's a liberating thing.
So that's our friend the monad.
That's it.
And we looked at three specific monads-- the identity
monad, the Ajax monad, the maybe monad.
There are lots more, but they're all
variations on this pattern.
And now that you've been through this talk, you might
want to look at the other monad tutorials.
Go to Bing and Google for monad burrito, and
see what you find.
It's going to be baffling stuff.
But it'll work.
So I have some time left.
So I want to talk about concurrency.
Concurrency is when you try to make lots of things happen at
the same time.
And there are a number of models for how you do that.
The most popular is to use threads.
And the problem with threads is that they are evil with
respect to mutation.
If you have a process that's trying to do read, modify,
write, and another process that's trying to do read,
modify, write, and they're doing it on the same memory,
there's a strong likelihood that they're going to clobber
each other.
That's called races.
And races are horrendously bad for reliability.
The way we mitigate that is with mutual exclusion.
Mutual exclusion has its own set of problems.
It can cause bad performance problems, or more likely it's
going to cause deadlocks and starvation.
And that's a bad thing too.
There are a couple of other alternatives.
One of them is to go with purely functional programming.
Because when we're purely functional, we never mutate.
And so that's not a problem.
But not mutating is its own problem.
Another alternative is turn based processing.
This, I think, is the right way forward.
So in a turn based system, everything is single-threaded.
An as a result we are race free and deadlock free.
That turns out to be great.
But it requires that we respect the law of turns.
The law of turns says, your code must never wait.
It must never block.
And it must finish fast.
A turn cannot sit there and loop, waiting for
something to happen.
It has to get out as quick as it can.
So not all programs can be easily adapted to that.
But it turns out quite a lot of them can.
So event driven systems tend to be turn based.
Message passing systems tend to be turn based.
You don't need threads.
You don't need mutual exclusion.
It's a much simpler programming model, and it's
really effective.
It turns out all web browsers use this model.
Most UI frameworks use this model.
So it's something we've been doing a long time, anyway.
We're now seeing this model getting more popularity on the
server side.
So there's Elko for Java.
There's Twisted for Python.
No JS for JavaScript.
Take the same turn based model, and make it available
on the server.
Now some people complain that asynchronicity
can be hard to manage.
And there are some things you need to do in
order to adapt to it.
One of the problems is that if you have multiple things that
each serially depend on each other, the naive way to write
that is with nested event handlers.
And that turns out to be extremely brittle patterns.
So you don't want to do that.
A much better alternative is to use promises.
Promises are objects which will represent a future value,
and a way of interacting with that future value.
So promises are an excellent mechanism for dealing with
asynchronicity.
Every promise has a corresponding resolver, which
is used ultimately to assign a value to that promise.
And once the value is assigned, then interesting
things can happen.
So a promise, when it's created, will have one of
three states.
First state will be pending.
And depending on what happens to it in the future, it can
change to either kept or broken.
Or it may always be pending.
So a promise is an event generator.
Once the promise is resolved, then it can fire events on
consumers who are interested in the result of the promise.
So at any time after making a promise, an event handling
function can be registered with the promise.
And those will then be called in the order in which they
were registered when the value was known.
And a promise can accept functions that will be called
with a value, once the promise has been kept or broken.
And we can do this with the when method.
The when is sort of like on.
It allows us to register event handlers, but it will register
two of them-- one to be called if the promise is kept, and
the other to be called it the promise is broken.
So here's a function for making up a promise.
I'm calling it vow.
So a vow will produce an object.
And that object will have three methods--
keep, break, or promise.
Promise is not actually method.
It's an object, which represents the promise itself.
So I can take the promise and hand it to you.
And in the future, when I know what the result of that
promise is, I can call either keep or break, and then your
promise will change its state, and good things happen.
So here's an example.
One of the problems with filesystem APIs, going all the
way back to Fortran, is that they block.
If I want to read something from the card reader, or from
the terminal, or if I want to send something to the printer,
or to the disk drive, my program stops until that
operation has completed.
In some cases, my program can stop for a long time.
I don't want to stop, because that breaks the law turns.
The law of turns says I never stop.
I never break.
I have to finish.
A way to do that would be to have the file system, instead
of blocking, it immediately returns a promise.
So my program can then continue going.
I'm not blocked on it.
So here I've got a read file instruction.
Name is probably the name of the file.
And it's going to return a promise.
And I can tell that promise, when you are resolved, call my
success function.
And it will receive the result of the file operation, and
things are good.
And if the file operation failed for some reason, like
file not found, or whatever, then call my
failure function instead.
You might be wondering why do you call my failure function?
Why don't you just throw an exception?
You have to think about this stuff as time travel.
So what an exception does is it unwinds the stack to some
earlier point in time.
And we can then recover from that point.
But in a turn based system, the stack gets reset all the
way down to zero at the end of every turn.
So there's no way I can unwind into a previous turn, because
the stack is gone.
There's no way to go back in time.
You can only go forward in time.
So we need eight time travel mechanism which goes forward.
It turns out promises do that.
That's the whole point.
So promises can have a positive consequence or a
negative consequence.
That negative consequence is like an exception.
So the way we deal with exceptions is by having
failure functions instead, which will be called in the
future, once we know that the thing actually failed.
I think I said all of that.
Exceptions modify the flow of control buy
unwinding the state.
Turn based system, the stack is emptied every turn.
One of the nice things about the way failure functions work
is that we can nest promises.
So each when actually returns another promise, based on the
resolution of that particular when.
And we can cascade those, as well.
So we can say, when we know the result of that, do this.
When we know the result of that, do that.
And so on.
And if any of those fail, and if they don't specify their
own failure, then the failure propagates.
It's contagious.
It goes forward.
And so the last one, the last failure specified, will catch
all of the previous things.
So it acts like a try, except this is something that's
happening over many, many turns.
So it gives us a way to manage asynchronicity.
So one of the nice things about promises and the when
method is how they compose.
So when I say .when.when, that's doing the same thing as
when passing in a function which calls
when on another promise.
And some of you might be thinking, wait a minute, this
looks eerily familiar.
Where have I seen this before?
You might be thinking, this looks like the third axiom.
I would say, you are right.
This is the third axiom.
It turns out promises are monads.
Now they're a different kind of monad, because all the
other ones we've looked at, the value of the monad is
known at the time that it's created.
And because it's purely functional, that value cannot
be modified.
This is a little different, because we don't know the
value at the time that the thing's created.
That's going to be resolved in the future.
So it gets filled in later.
Also because monads don't have the problem where they might
fail to ever get that value, we only need to provide one
function to bind.
But when needs the ability to have two functions, because it
has to deal with a failure case.
But otherwise, it works exactly like the monads.
Let's look at how we could build the vow function in
order to do this.
Now this is about a page worth of code.
And I'll show you the page at the end, but you're not going
to be able to read it.
So I'm going to be zooming in on pieces of it.
So we've got a function that is going to return an object.
And that function is going to have a couple of functions in
it that the yellow function will close over.
That's one of the nice construction
patterns that we have.
And the thing that we're assigned to vow is not the
green function, it's the result of the green function.
Because we're invoking it here, at the bottom.
So that little pair of parens is really easy to overlook.
But it turns out it's really critical to
understanding this.
So just leaving it hanging out there like a pair of dog
balls, I don't think is useful to the reader.
I want the reader to have a bigger clue
that this is important.
So I recommend wrapping the entire implication
expression in parens.
So it makes a lot easier for the reader to see this is all
part of the same thing.
This is important.
If I see a function in parens, that probably means something.
And I need to look for that.
OK, so let's zoom in on the make function.
It's going to have a couple of arrays where it's going to
keep the success functions and failure functions that get
registered with it.
It's going to have a variable for the ultimate fate of this
promise, once it's known.
Its status starts off as pending.
JavaScript doesn't have symbols.
It doesn't really need them, because strings were
implemented correctly.
Two strings containing the same
letters are equal, which--
it would be stupid for them not to be equal, wouldn't it?
And then it returns of an object containing the break
method, the keep method, and the promise
itself, which is an object.
We'll look at its construction in a moment.
And break and keep both call a herald function, which is
going to announce to the world the
resolution of this promise.
So we'll look at herald.
Herald can only be called once.
So if the current state is not pending, then we can throw.
In this case, throwing is OK, because it's a local thing.
It's not something that we need to throw
into a different turn.
We'll set the fate, and we will enlighten the queue of
waiters, and let them know that the fate is known.
And we'll then zero out the two queues to make sure that
none of those functions ever get called again.
So let's zoom in on something else now.
We're going to zoom in on the promise.
The promise will have a property that just identifies
itself as a promise, to make it a little easier to
recognize it.
And it contains the when method.
The when method is going to register the two event
handlers that depend on the result of the promise.
And how it will do that will depend on the current state of
the promise.
If they're pending, then they simply get added to the queue.
If the promise has already been resolved, then it will,
depending on whether we're relying on the failure case or
the other case, will queue it and then enlighten
immediately.
So it doesn't matter when the promise is resolved versus
when we register with the when method.
So there's no race there.
You can register after the promise is resolved, and it
works exactly the same way.
You don't need to care about how that race may occur.
And then at the end, we return the promise.
This is the business that happens when cue the thing.
I'm getting bored now, so I'm just going to skip through
this stuff.
And there's that.
So the code is available on GitHub, if you want
to play with it.
It's all written in JavaScript.
This is it.
There's just one page.
You might want to write that down.
So our friend, the monad.
So we saw the identity monad, the Ajax monad, the maybe
monad, and the promise monad.
I contend that promises are monads, which--
this is my contribution to this, I guess.
I don't think this result had been known before.
Don't forget your semicolons, people.
It's really important.
I've got some further viewing for you.
Carl Hewitt was at MIT.
I think he's at Stanford now.
He came up with the actor model, which inspired the
development of the scheme language, and a
lot of other stuff.
I think the actor model contains the solution to most
of our problems.
But Carl has not written any accessible material about it.
It's all kind of--
you're read it, obviously.
It's scary stuff.
But he did do an interview with
Channel Nine at Microsoft.
It's actually a very nice introduction to the stuff.
So I recommend you take a look at that.
Channel Nine apparently likes the really long URLs.
I doubt that there's anybody in this room who could
actually type that in.
I'm sure if you go search for it, you should be
able to find it.
Then Mark Miller is one of the first people to come up with
promises, which is based on an idea called futures, which
also came out of Carl's actor model.
He's implemented it in a number of languages.
And you just saw an implementation in JavaScript.
He has a really interesting couple of talks that are
available on YouTube, which talk about this, and some of
its implications for doing automated contracting, and
financial instruments, and lots of other really
interesting stuff.
So I recommend you take a look at that as well.
It's certainly worth your time.
And Miller works here, by the way.
He is a Googler, good guy.
And that's it.
That's all I've got for you this hour.
Think you and good night.
MALE SPEAKER: I'm guessing you have a few minutes, maybe to
answer a couple of questions?
In an effort to keep the video in sync with questions, I've
got a lav here.
So I walk around to anybody who wants to ask a question,
just so we can capture it.
And while we're talking about that, nothing
confidential, please.
This will be going public afterwards.
Do you want to start?
AUDIENCE: Thanks for the talk.
I was wondering, what's your take on the
cancellation of promises?
Because that's one of the questions that hasn't been
really resolved.
Cancellation of promises, when I register my listener to a
promise, and I'm not interested
in the result anymore.
DOUGLAS CROCKFORD: So that's a really easy thing to resolve
on your side.
You can have a Boolean at the top of your responder, which
says, am I interested anymore or not.
So you can do it that way.
But promises also compose really nicely.
You can cascade them together and stuff.
So you can have a canceller in that string.
You can compose cancellation.
There are lots of higher level patterns that you can build
out of the simple promises.
AUDIENCE: Is there a way to communicate to the resolver
that you are not interested anymore, therefore it doesn't
need to do the work to generate--
DOUGLAS CROCKFORD: Is there a way to
communicate to the resolver?
Not in the promise system itself.
But you can always send it message.
And it's similar to a problem you might have in, say timers.
You can have a queue of timers.
You might want to say, I'm not interested in this timer
anymore, and so you want to cancel it.
But it might be that by the time you get the cancellation
to it, it's already fired.
So it's likely you're going to experience races.
So that's probably not a pattern you want to pursue.
But it is available to you.
AUDIENCE: It seems that debugging is a real challenge
for turn based programming.
If you set a break point in a conventional program, you can
see the call chain that gave you the context
for why you're there.
You could step over subfunctions, and skip whole
sub trees of the evaluation tree.
And that seems to be a lot more complicated in debugging.
Is there practical tools for debugging turn based programs?
DOUGLAS CROCKFORD: I think it's a lot easier than trying
to debug threads.
The hardest thing I've ever done in my career is try to
debug a real time problem where two threads were chasing
each other.
I think turns are a lot easier to manage than that.
Debugging is always going to be hard.
And as we get more temporal complexity, it gets harder.
But I think turns manage that complexity much better than
threads do.
MALE SPEAKER: As soon as I have the floating mic, I'm
going to make my way to the front in a second.
We've got one more here.
AUDIENCE: Do you have any thoughts on emulating
do-notation in JavaScript?
Have there been any attempts at that?
DOUGLAS CROCKFORD: Thoughts on what?
AUDIENCE: Emulating do-notation?
The monadic do syntax.
DOUGLAS CROCKFORD: No.
One thing we're seeing in JavaScript now is a lot of
experimentation with new syntax.
Coffee scripts launched that--
there were other examples before that.
But there are lots of people who were trying to experiment
with changing language, or making it more expressive.
I expect we'll see that research continue.
We don't see promises as a feature in the
ES6, possibly ES7.
But I'm not confident as to what's going to make in the
ES6 right now.
So it's dangerous to predict what's going to be in seven.
And whether it will bring new syntax with it as well, I
don't know.
AUDIENCE: Is the cost of making closures in JavaScript
make these monadic approaches infeasible right now?
DOUGLAS CROCKFORD: No,
closures aren't that expensive.
They're just function objects.
And they're great.
A lot of stuff gets enabled by this.
You could take a simpler approach to
some of these things.
There is a cost.
But very few of our JavaScript programs are compute bound.
We're mostly bound by everything else.
So I don't think it's a concern.
I think this is easily affordable.
AUDIENCE: Is this a public video?
MALE SPEAKER: Yes.
Any non-competition questions?
You guys are quite a bunch.
All right, I think you stunned into silence, Douglas.
DOUGLAS CROCKFORD: All right.
Thank you.