Home > Mobile >  These concepts about Functors (Maps) and Monads (Either, Maybe, Bind, Then) are right?
These concepts about Functors (Maps) and Monads (Either, Maybe, Bind, Then) are right?

Time:09-17

I'm relatively new studying functional programming and things were going well until I had to treat errors and promises. Trying to do it in the “right” way I get a lot of references for Monads as to be the better solution for it, but while studying it I ended up with what I honestly would call a "reference hell", where there was a lot of references and sub-references either mathematical or in programming for the same thing where this things would have different name for the same concepts, which was really confusing. So after persisting in the subject, I'm now I trying to summarize and clarify it, and this is what I get so far:

For the sake of the understanding I'll oversimplify it.

Monoids: are anything that concatenate/sum two things returning a thing of the same group so in JS any math addition or just concatenation from a string are Monoids for definition as well the composition of functions.

Maps: Maps are just methods that apply a function to each element of a group, without changing the category of the group itself or its length.

Functors: Functors are just objects that have a Map method which return the Functor itself.

Monads: Monads are Functors that use FlatMaps.

FlatMaps: FlatMaps are maps that have the capability of treat promises/fetch or summarize the received value.

Either, Maybe, Bind, Then: are all FlatMaps but with different names depending of context you use it.

(I think they all are FlatMaps for definition but that there is difference in the way they are used, since there is library like Monets.js that have both a Maybe and a Either function, but I don’t get the use case difference).

So my question is: are these concepts right?

if anyone can reassure me what so far I got right and correct what I got wrong, or even expand on what I have missed, I would be very grateful.

Thanks to anyone who take the time.

//=============================================================//

EDIT: I should've emphasized more in this post, but this affirmations and simplified definitions are only from the "practical perspective in JavaScript" (I'm aware of the impossibility of made such a small simplification of a huge and complexe theme like these especially if you add another field like mathematics).

//=============================================================//

CodePudding user response:

Monoids: are anything that concatenate/sum two things returning a thing of the same group...

First thing that I don't like here is the word “group”. I know, you're just trying to use simple language and all, but the problem is that group has a very specific mathematical meaning, and we can't just ignore this because groups and monoids are very closely related. (A group is basically a monoid with inverse elements.) So definitely don't use this word in any definition of monoids, however informal. You could say “underlying set” there, but I'd just say type. That may not match the semantics in all programming languages, but certainly in Haskell.

So,

Monoids: are anything that concatenate/sum two things returning a thing of the same type so in JS any math addition or just concatenation from a string are Monoids for definition as well the composition of functions.

Ok. Specifically, concatenation of endofunctions is a monoid. In JavaScript, all functions are in a sense endofunctions, so you can get away with this.

But that's actually describing only a semigroup, not a monoid. (See, there's out groups... confusingly, monoids are in between semigroups and groups.) A monoid is a semigroup that has also a unit element, which can be concatenated to any other element without making a difference.

  • For the addition-monoid, this is the number zero.
  • For the string-monoid, it is the empty string.
  • For the function monoid, it is the identity function.

Even with unit elements, your characterization is missing the crucial feature of a semigroup/monoid: the concatenation operation must be associative. Associativity is a strangely un-intuitive property, perhaps because in most examples it seems stupidly obvious. But it's actually crucial for much of the maths that is built on those definitions.

To make the importance of associativity clear, it helps to look at some things that are not semigroups because they aren't associative. The type of integers with subtraction is such an example. The result is that you need to watch out where to put your parentheses in maths expressions, to avoid incurring sign errors. Whereas strings can just be concatenated in either order – ("Hello" ", ") "World" is the same as "Hello" (", " "World").

Maps: Maps are just methods that apply a function to each element of a group, without changing the category of the group itself or its length.

Here we have the next badly chosen word: categories are again a specific maths thing that's very closely related to all we're talking about here, so please don't use the term with any other meaning.

IMO your definitions of “maps” and functors are unnecessary. Just define functors, using the already known concept of functions.

But before we can do that –

Functors: Functors are just objects...

here we go again, with the conflict between mathematical terminology and natural language. Mathematically, objects are the things that live in a category. Functors are not objects per se (although you can construct a specific category in which they are, by construction, objects). And also, itself already conflicting: in programming, “object” usually means “value with associated methods”, most often realized via a class.

Your usage of the terms seems to match neither of these established meanings, so I suggest you avoid it.

Mathematically, a functor is a mapping between two categories. That's hardly intuitive, but if you consider the category as a collection of types then a functor simply maps types to types. For example, the list functor maps some type (say, the type of integers) to the type of lists containing values of that type (the type of lists of integers).

Here of course we're running a bit into trouble when considering it all with respect to JS. In dynamic languages, you can easily have lists containing elements of multiple different types. But it's actually ok if we just treat the language as having only one big type that all values are members of. The list functor in Python maps the universal type to itself.

Blablatheory, what's the point of this all? The actual feature of a functor is not the type-mapping, but instead that it lifts a function on the contained values (i.e. on the values of the type you started with, in my example integers) to a function on the container-values (on lists of integers). More generally, the functor F lifts a function a -> b to a function F(a) -> F(b), for any types a and b. What you called “category of the group itself” means that you really are mapping lists to lists. Even in a dynamically typed language, the list functor's map method won't take a list and produce a dictionary as the result.

I suggest a different understandable-definition:

Functors: Functors wrap types as container-types, which have a mapping method that applies functions on contained values to functions on the whole container.

What you said about length is true of the list functor in particular, but it doesn't really make sense for functors in general. In Haskell we often talk about the fact that functor mapping preserves the “shape” of the container, but that too isn't actually part of the mathematical definition.

What is part of the definition is that a functor should be compatible with composition of the functions. This boils down to being able to map as often as you like. You can always map the identity function without changing the structure, and if you map two functions separately it has the same effect as mapping their composition in one go. It's kind of intuitive that this amounts to the mapping being “shape-preserving”.

Monads: Monads are Functors that use FlatMaps.

Fair enough, but of course this is just shifting everything to: what's a FlatMap?

Mathematically it's actually easier to not consider the FlatMap / >>= operation at first, but just consider the flattening operation, as well as the singleton injector. Going by example: the list monad is the list functor, equipped with

  • The operation that creates a list of just a plain contained value. (This is analogous to the unit value of a monoid.)
  • The operation that takes a nested list and flattens it out to a plain list, by gathering all the values in each of the inner lists. (This is analogous to the sum operation in a monoid.)

Again, it is important that these operations obey laws. These are also analogous to the monoid laws, but unfortunately even less intuitive because their simultaneously hard to think about and yet again so almost-trivial that they can seem a bit useless. But specifically the associativity law for lists can be phrased quite nicely:

Flattening the inner lists in a doubly nested list and then flattening the outer ones has the same effect as first flattening the outer ones and then the inner ones.

[[[1,2,3],[4,5]],[[6],[7,8,9]]] ⟼ [[1,2,3,4,5],[6,7,8,9]] ⟼ [1,2,3,4,5,6,7,8,9]
[[[1,2,3],[4,5]],[[6],[7,8,9]]]⟼[[1,2,3],[4,5],[6],[7,8,9]]⟼[1,2,3,4,5,6,7,8,9]

CodePudding user response:

A Monoid is a set and an operator, such that:

  1. The operator is associative for that set
  2. The operator has an identity within that set

So, addition is associative for the set of real numbers, and in the set of real numbers has the identity zero.

a (b c) = (a b) c  -- associative
a 0 = a            -- identity

A Map is a transformation between two sets. For every element with the first set, there is a matching element in the second set. As an example, the transformation could be 'take a number and double it'.

The transformation is called a Functor. If the set is mapped back to itself, it is called an Endofunctor.

If an operator and a set is a Monoid, and also can be considered an Endofunctor, then we call that a Monad.

Monoids, Functors, Endofunctor, and Monads are not a thing but rather the property of a thing, that the operator and set has these properties. Can we declare this in Haskell by creating instances in the appropriate Monoid, Functor and Monad type-classes.

A FlatMap is a Map combined with a flattening operator. I can declare a map to be from a list to a list of lists. For a Monad we want to go from a list to a list, and so we flatten the list at the end to make it so.

  • Related