Multiple flatMap methods for one monad?

Does it make sense to define several flatMap methods (or >>= / bind in Haskell) in Monad? The very few monads that I use ( Option , Try , Either projections) define only one flatMap method.

For example, can it make sense to define a flatMap method on Option that will take a function that creates Try ? To Option[Try[User]] was flattened as Option[User] for example? (Considering loss of exception is not a problem ...)

Or should a monad simply define one flatMap method, taking a function that creates the same monad? I think in this case the projections of Either would not be monads? They?

+6
source share
4 answers

I somehow seriously thought about it. As it turned out, such a design (except for the loss of all monadic capabilities) is not interesting, since it is enough to provide conversion from internal to external container:

 joinWith :: (Functor m, Monad m) => (na -> ma) -> m (na) -> ma joinWith i = join . (fmap i) bindWith :: (Functor m, Monad m) => (na -> ma) -> ma -> (a -> na) -> ma bindWith ixf = joinWith i $ fmap fx *Main> let maybeToList = (\x -> case x of Nothing -> []; (Just y) -> [y]) *Main> bindWith maybeToList [1..9] (\x -> if even x then Just x else Nothing) [2,4,6,8] 
+5
source

It depends on what “meaning” means.

If you mean that this is consistent with the laws of the monad, then it is not entirely clear to me that the question makes sense. I will need to see a specific sentence to tell. If you do it as it seems to me, you will probably end up breaking the roster, at least in some cases.

If you mean this is useful, of course, you can always find cases where such things are useful. The problem is that if you start violating the laws of the monad, you will leave traps in your code for careless functional (category theory theories). Better to do things that look like monads are actually monads (and only one at a time, although you can provide an explicit way to switch la Either ), but you are right that, as written by LeftProjection and RightProjection , strictly speaking, are not monads) . Or write really clear documents explaining that this is not what it looks like. Otherwise, someone will have fun walking, considering the laws to be held, and * splat *.

+1
source

For a certain data type, it makes no sense, as far as I know, for bind can be only one definition.

In haskell, the monad is the next type of class,

 instance Monad m where return :: a -> ma bind :: ma -> (a -> mb) -> mb 

Specifically, for the list of Monad we have,

 instance Monad [] where return :: a -> [] a (>>=) :: [] a -> (a -> [] b) -> [] b 

Now consider the monadic function as.

 actOnList :: a -> [] b .... 

A usage example to illustrate

 $ [1,2,3] >>= actOnList 

In the actOnList function actOnList we see that a list is a restriction of a polymorphic type to another type (here [] ). Then, when we talk about the binding operation for the list monad, we talk about the binding operator defined by [] a -> (a -> [] b) -> [] b .

What you want to achieve is the bind operator, defined as [] Maybe a -> (a -> [] b) -> [] b , this is not a special version of the first, but another function, and with respect to this signature of type I really doubt it could be the bind operator of any monad, since you are not returning what you consume. You are sure to switch from one monad to another using a function, but this function is definitely not a different version of the list bind operator.

That's why I said: "It doesn’t make sense, for a certain data type, as far as I know, you can only have one definition for bind .

+1
source

flatMap or (>>=) not suitable for your example Option[Try[ ]] . In the notation of pseudo-Haskell

 type OptionTry x = Option (Try x) instance Monad OptionTry where (>>=) :: OptionTry a -> (a -> OptionTry b) -> OptionTry b ... 

We need bind / flatMap to return a value enclosed in the same context as the input value.

We can also see this by looking at the equivalent implementation of return / join Monad. For OptionTry join has a specialized type

 instance Monad OptionTry where join :: OptionTry (OptionTry a) -> OptionTry a ... 

In short, it should be clear that the "flat" part of flatMap is join (or concat for the lists from which the name comes).

Now it is possible that for one data type there may be several different bind s. Mathematically, a Monad is actually a data type (or, indeed, a set of values ​​that make up a monad), as well as specific bind and return operations. Different operations lead to different (mathematical) Monads.

+1
source

Source: https://habr.com/ru/post/944396/


All Articles