It's a bit more powerful than that - consider what would happen if, every time you sequence two statements together...
doThingOne(); doThingTwo()
... you get to pick what happens during the semicolon depending on which Monad you happen to be working with.
For example, like praptak mentioned, maybe during every semicolon you can evaluate the failure state of your program and decide not to continue. I.E., "Maybe" the execution worked, and "Maybe" I have a valid computation at this point, but "Maybe" not!
The power here is that while you are really operating in this context with an implicit possibility of having failure, you can program as if each step succeeded. So now we can string together a whole sequence of possibly-failing computations, and create a bigger possibly-failing super-computation that error checks under the hood.
The context isn't a property of the monad abstraction, but
of a concrete monad, like the State monad.
If you desugar everything from the State monad, than you
can see, that the state 'c' is an explicit argument, which
is hidden in the "sugared" version.
import Control.Monad.State.Lazy
type Counter = State Int
-- using the State monad and the do notation
increment :: Counter ()
increment = do
c <- get
put $ c + 1
-- using the State monad and desugar the do notation
increment_ :: Counter ()
increment_ = get >>= \c -> put $ c + 1
-- desugar 'get'
get_ = \c -> (c, c)
-- desugar 'put'
put_ c = \_ -> ((), c)
-- desugar >>=
bind_ a b = \c -> let (result, c') = a c in (b result) c'
-- "desugar" the State monad
increment__ = get_ `bind_` \c -> put_ $ c + 1
I may be misunderstanding you, but from your description, that more describes functors than it does monads. The difference being that in a monad, the `someFunc` you pass in is responsible for creating a new context (of the same monad type).
Pretending that javascript is immutable, I think it would probably look something more like
contextObj = monadBox(myObj)
// someContextReturningFunc gets myObj as its argument from contextObj and generates newContextObj
newContextObj = monadBind(contextObj, someContextReturningFunc)
newNewContextObj = monadBind(newContextObj, someOtherContextReturningFunc)
...
To make this more concrete, let's take the Maybe monad/functor in javascript and compare them. The Maybe monad is described by johnpmayer elsewhere here.
// Creating maybe "contexts"
maybeNothing = {maybe: "nothing"}; // maybeMonad holding nothing
maybeJust = function(x) { return {maybe: "just", just: x} }; // create a maybeMonad holding a (the '[a]' in the picture)
// Monadic bind
function maybeBind(maybeMonad, f) {
// maybeMonad is '[a]' in the picture
if (maybeMonad.maybe === "just") {
return f(maybeMonad.just); // expects f to return another maybeMonad '[b]'
} else {
return maybeNothing; // also '[b]' but the b value doesn't really exist
}
}
// Functor map
function maybeMap(maybeMonad, f) {
// maybeMonad is '[a]' in the picture
if (maybeMonad.maybe === "just") {
return maybeJust(f(maybeMonad.just)); // expects f to return a value without any maybe stuff ('a -> b')
// notice that the monad wrapping remains separate from f
} else {
return maybeNothing;
}
}
// Functor examples
//////
// possible values of 'f', note that maybe is not involved at all
function addOne(x) { return x + 1; }
// usage
console.log(maybeMap(maybeJust(1), addOne)); // returns maybeJust(2)
console.log(maybeMap(maybeNothing, addOne)); // returns maybeNothing
// Monad examples
//////
// possible values for 'f', notice x is what was contained in the maybe (not the maybe itself) and the return is a maybe
function maybeAddOneIfOdd(x) { return (x % 2 == 0) ? maybeNothing : maybeJust(x + 1); };
function maybeAddThree(x) { return maybeJust(x + 3); };
// usage
console.log(maybeBind(maybeJust(1), maybeAddThree)); // returns maybeJust(4)
console.log(maybeBind(maybeJust(1), maybeAddOneIfOdd)); // returns maybeJust(2)
console.log(maybeBind(maybeBind(maybeJust(1), maybeAddThree), maybeAddOneIfOdd)); // returns maybeNothing (due to 4 being even)
console.log(maybeBind(maybeBind(maybeJust(2), maybeAddOneIfOdd), maybeAddThree)); // returns maybeNothing because the first bind returned nothing
// and of course, composition
function maybeMultiplyThree(x) { return maybeJust(x * 3); }
function maybeMultiplyThreeThenAddOneIfOdd(x) {
return maybeBind(maybeMultiplyThree(x), maybeAddOneIfOdd);
}
console.log(maybeBind(maybeJust(1), maybeMultiplyThreeThenAddOneIfOdd)); // returns maybeJust(4)
console.log(maybeBind(maybeJust(2), maybeMultiplyThreeThenAddOneIfOdd)); // returns maybeNothing
There's more to monads. One important feature is separation of composition from execution. Second one is that the composition can do some extra things automatically, for example the Maybe monad composes functions in such a way that if the first function produces 'Nothing', the second will not be evaluated.
Comments
from a non-Haskell programmer here. It looks like monads are just a way to call functions in difference context, in js
Or am I missing something here?It's a bit more powerful than that - consider what would happen if, every time you sequence two statements together...
... you get to pick what happens during the semicolon depending on which Monad you happen to be working with.For example, like praptak mentioned, maybe during every semicolon you can evaluate the failure state of your program and decide not to continue. I.E., "Maybe" the execution worked, and "Maybe" I have a valid computation at this point, but "Maybe" not!
The power here is that while you are really operating in this context with an implicit possibility of having failure, you can program as if each step succeeded. So now we can string together a whole sequence of possibly-failing computations, and create a bigger possibly-failing super-computation that error checks under the hood.
ok, gotcha that is a pretty nifty feature :)
The context isn't a property of the monad abstraction, but of a concrete monad, like the State monad.
If you desugar everything from the State monad, than you can see, that the state 'c' is an explicit argument, which is hidden in the "sugared" version.
I may be misunderstanding you, but from your description, that more describes functors than it does monads. The difference being that in a monad, the `someFunc` you pass in is responsible for creating a new context (of the same monad type).
Pretending that javascript is immutable, I think it would probably look something more like
To make this more concrete, let's take the Maybe monad/functor in javascript and compare them. The Maybe monad is described by johnpmayer elsewhere here. Edit: added some extra examples and commentsThere's more to monads. One important feature is separation of composition from execution. Second one is that the composition can do some extra things automatically, for example the Maybe monad composes functions in such a way that if the first function produces 'Nothing', the second will not be evaluated.