4 ms·
from a non-Haskell programmer here. It looks like monads are just a way to call functions in difference context, in js map(myObj, someFunc, contextObj) Or a
by jfaucett 14y ago
from a non-Haskell programmer here. It looks like monads are just a way to call functions in difference context, in js
map(myObj, someFunc, contextObj)
Or am I missing something here?
- praptak 14y agoThere'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.
- johnpmayer 14y agoIt'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.
- jfaucett 14y agook, gotcha that is a pretty nifty feature :)
- jochu 14y agoI 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 Edit: added some extra examples and comments
- dan00 14y agoThe 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
- deleted 14y ago[deleted]