5 ms·
Minor nit, but I believe that his description of the async pattern in future is not only monadic, but also comonadic.
by Locke1689 13y ago
Minor nit, but I believe that his description of the async pattern in future is not only monadic, but also comonadic.
- eru 13y agoYes, but only if you turn a blind eye to `get' being a partial function (ie it might fail or diverge).
- theophrastus 13y agoi prefer "holoambiadic". in all relative seriousness, would anyone care to put forward a concise definition of "monad" (for programmers, not math-category-theorists)?
- spion 13y agoFunctor is something that has a map function. A monad is any generic class that has a flatMap function and a factory function that together satisfy 3 laws (explained below) flatMap is like map, except the function passed to flatMap must return a monad (of the same kind). The factory can make a monad of a regular value (it wraps it) For example, an array's flatMap function takes a function that takes an element and returns an array. You can return an empty array if you wish, or an array of two elements (of the same type). flatMap "flattens" the result - it returns an array of elements of that same type. The factory function and flatMap must satisfy 3 laws: left identity, right identity and associativity. That is, flatMapping with the factory function should result with the same thing as what you started with; wrapping a value with a factory then flatMapping it should result with that same value being passed to the function you passed to flatMap; and it shouldn't matter whether multiple flatMap calls are chained, or nested. Like design patterns in OO languages, it isn't immediately clear why its useful to give a name (or a type) to all generic classes that satisfy this "interface" called monad, but it turns out that the concept pops up everywhere, from arrays to futures to Maybe (to replace null values) to Either to Observable and so on. Not sure if I managed to be correct, understandable, concise or neither :P
- theophrastus 13y agook i'm going on a limb here and suggest that you're probably "correct". but you need to use more terms selected from the following list (random usage is encouraged but idempotent): closure, adjoint, operator, endofunctor, universal algebra, maybe, iteratee, continuation, surjective, type constructor, simonpeytonjonesing
- axman6 13y agoTo start with, Functor gives an generic interface (fmap) allowing you to take Foo<A> and a function B f(A) and apply it to get Foo<B> Then monad gives us something called join, which lets us take: Foo<Foo<A>> and turn it into Foo<A> It's pretty obvious that a Vector of Vectors of A's can be turned into a Vector of A's by concatenating them into one Vector. Also optional (something I don't know much about, sorry) can be turned from Optional<Optional<A>> into Optional<A> if the outer actually contains an inner optional, and the inner optional contains an A. So with these two things, we can do things like: Vector<B> f(A); Vector<C> g(B) Vector<A> foos = {a,b,c}; foos.fmap(f).join().fmap(g).join() to get a Vector<C>. The result is basically considered all possible results of applying f to all the values in foos, and then applying g to all the values returned by all the calls to f. this is the non-deteminism monad, where each function f and g can produce multiple results (including none) for each input, and we can chain multiple non-deterministic computations to get all the non-deterministic results. Usually Mopnad is explained with return and bind, but I think it's a bit less obvious. But I'll give it a shot... bind in Haskell is something that takes something of type Foo<A> and a function with type Foo<B> f(A) and produces something of type Foo<B> From above, we can rewrite the example with Vector<B> f(A) Vector<C> g(B> Vector<A> foos = {a,b,c}; foos.bind(f).bind(g); and get the same result as before. I guess you could use slightly cleaner syntax (why the hell not overload >> for yet another bizarre use right? [leading to foos >> f >> g;]) I hope that you can see that this is just a simple interface which can work for many types that look like Foo<a> (Vector, Set [assuming C++ has that?], Optional, even pointers to some extent; see the discussions of the introduction of "?." into C# which is exactly what the Maybe monad encodes). There are also plenty of other monads in the haskell universe which aren't as easy to show in C++ because a) I'm not sure C++'s type system is up to it and b) my C++ knowledge is not strong enough to demonstrate things like the State monad, and definitely the Cont[inuation] monad. Anyway, bring it back to the topic of the article, it should be clear that something of type Future<A> can be composed with other functions w3hich produce more Futures: Future<B> f(A); Future<C> g(B); Future<A> async_A("thing"); asyc_A.bind(f).bind(g); Which handles all the unwrap and passing of values "inside" the future to each consecutive function. I know this isn't a concise explanation, but it's because it's a very simple, but also very abstract idea, and its best introduced with example uses, then generalising it.