4 ms·
May be. I think a Monad is an abstraction which generalizes a transition, similar to a step of logical deduction. It Haskell a similar concept is actually used
by throwaway487549 8y ago
May be. I think a Monad is an abstraction which generalizes a transition, similar to a step of logical deduction.
It Haskell a similar concept is actually used to compose what they call actions, originally used to implement IO. Out of this particular design choice, there are some specialized instances of Monads in Haskell, including State Monad.
In the context of a lazy language, like Haskell, where the order of evaluation is not defined and each expression is an implicit thunk, monadic composition is necessary and sufficient to implement serialized sequenced actions, defined as different instances of Monad type-class and to ensure, by the type checker, that these actions are of proper type (isolated from any other instances) and are properly serialized. Just this.
As a consequence of being desugared into function composition with parameter passing (>>=), which is only relevant for a lazy language, there is literally no way to access the state from outside of each pair of nested functions, so things like ST or STM are implemented as Monad.
All this is relevant for Haskell and irrelevant in Scala, where you don't have to compose functions to ensure order of evaluation. Algebraic data types and "semicolons" is good-enough.
- john_courtland 8y ago> All this is relevant for Haskell and irrelevant in Scala, where you don't have to compose functions to ensure order of evaluation. Promises and Futures are counterexamples to your claim here.
- throwaway487549 8y agoPromises and futures in Scala standard library and in Akka have nothing to do with Monads.
- mlazos 8y agoI don’t think your thinking about ordering is correct, in fact I remember reading a blog post somewhere (can’t seem to find it now) that made these same claims and was really confusing/poorly written, I’m wondering if you also read it. Anyway, monads can be about ordering but aren’t necessarily always used for this purpose, an example of a monad that doesn’t order operations is the Reader monad. I generally think about monads as generalizing composition, and not necessarily “transitions” because there are some contexts (ie Reader) where “transition” doesn’t really fit what’s happening in the computation.
- tathougies 8y agoA monad is a descriptive term for certain objects with have certain properties. For example, a ring in algebraic theory is a set together with two operations (+ and ) with certain properties. The natural numbers (1,2,3,...) together with + being addition and being multiplication form a ring, but to say that 'the natural numbers were constructed as a ring' or that 'a ring is an abstraction for the natural numbers' is wrong. Both rings and natural numbers are descriptions of things which happen to fit. Similarly, category theory monads are a description of things with certain properties. These happen to be satisfied by IO actions in every language and Promises in JavaScript. Haskell allows you to define this abstraction within the language, but it is not the only language that allows this.
- mikekchar 8y ago> I think a Monad is an abstraction which generalizes a transition, similar to a step of logical deduction. I think this is where we're going off the rails. A monad is a specialisation of a functor (the infamous "A monad is monoid in the class of endofunctors", which I'll explain as briefly as I can later). A functor is simply a mapping from one set to another (possibly the same set). So if I have a function that maps integers to characters, for instance this whole setup (the set of integers, the set of characters and the function that maps them from one to the other) is a functor. It gets a bit complicated when we translate that to a programming language. The set of all integers is a type. The set of all characters is a type. So we can describe the mapping from one to the other as a functor. You will probably just recognise that as a function -- and, indeed, a function is a specialisation of a functor (although the general case of a function is quite complex and I don't have anywhere enough space to explain it). What is important to understand, though, is that the thing we are trying to map is important. We need somewhere to hold that value so that we can map it from one type to another type. Any container will do (a list, array, tuple, or even a partially applied function). When we are talking about programming with functors, we implement them using that container and a function that transforms the content from one type to another (possibly the same type). When we map the value from one type to another, we want to put the value in a functor as well (going back to the original concept of mapping from one set to another, after we've mapped it, it is still a functor -- just one potentially holding a different typed value). Normally we implement a function called "map" (or "fmap", for "functor map") on a functor that accepts a transforming function that maps a value from one type to another. "map" then puts the result back into a functor (which is just the same kind of container you started with). As I can see you are familiar with FP languages, I'm sure you are familiar with this implementation. You have an array of integers, you can call "map" with a function that maps integers to characters and the result is an array of characters. Both the array of integers and the array of characters are functors. Again, I'll reiterate this because it will be super important later: any container is a functor if you can map it's contents. In fact, anything that can hold state (like a partially applied function) is a functor if you can map its contents. A monad is a specialisation of a functor. Let's go back to "A monad is a monoid in the category of endofunctors". I like that quote because it sounds like nonsense, but it's really very easy to understand if you know the definitions of the words. A "monoid" is another specialisation of a functor. It's a functor for which there is a binary operator and an identity element. For example, let's take integers. They are monoids under addition. If we take 2 integers and add them together. There is a particular integer, "0" for which when you add anything to "0" you get the same result again. We can use addition in our mapping function (usually one of the parameters being partially applied) and if we pass it "0" we'll get the same value back. Monoids seem a bit pointless, but they make a lot more sense when you are thinking about folding. A container isn't foldable unless is is a monoid (it's a great kata to do, if you are interested). There are lots of other implications, so I highly recommend implementing the whole hierarchy of functors from scratch to see why things are as they are. Getting on to monads, we now know what a monoid is (not too difficult to understand). We only need to know what an "endofuctor" is. This one is also really easy to understand. An endofunctor is a functor for which the result of "map" results in exactly the same type as the original. So if you had an array of integers to start with, you end up with an array of integers. That's all it is. "A monad is a monoid in the category of endofunctors". The last bit we have to explain is what a category is. It's just a grouping of mappings. I could have a mapping that adds 5 to an integer. I could have a mapping that adds 6 I could have one that subtracts 1. Each one of those mappings gives a result in the set of integers. As a grouping of mappings (i.e. "category"), all of these mappings describe an "endofunctor". Finally we get to the result. In very plain terms, a monad is just a container (or anything that can hold state) which has a function that modifies the contents such that the result is guaranteed to have exactly the same type. That's all it is. It sounds disappointingly plain, but it has surprising power. For one thing a monad holds state. Obviously this is important. But if you use the monadic mapping function (usually called "bind"), then you are guaranteed to be returned a monad of the same type. This allows you to freely chain operations without fear that something will break. This is what a monad is for. Where I think you are getting confused is that you have seen advanced applications of monads and you have come under the mistaken impression that these are the reasons monads exist. Indeed, monads are required in a pure functional language to do those things. The nice thing about a monad is that it can hold any state for which there is an identity element. The implementation of the container is completely beside the point. As I said, you can partially apply a function and that is potentially a monad. The even more interesting thing is that any abstract datatype can also be a monad. Where you are saying, "We don't need monads for this, we only need abstract data types", it's a bit nonsensical. These ADTs will be monads if they are used in that fashion. Indeed, objects in OOP are often monads! They just need a transforming function that returns the same type of object. I hope you found that interesting/helpful.