I wrote an explanation of fmap vs bind but then I realized the problem here is that for some reason the function needs to be in the left hand side of the <|> operator.
Functor.fmap takes a value and then a function: MonadEx/functor.ex at master Β· rob-brown/MonadEx Β· GitHub
But <|> reverses the order: MonadEx/operators.ex at master Β· rob-brown/MonadEx Β· GitHub
So I think your function should do (&plus_1/1) <|> (&plus_1/1) <|> success(x) instead?
The explanation I started to write in case you want it:
The way to chain monads is by using bind, not fmap.
bind's signature is bind :: m a -> (a -> m b) -> m b where m is the monad(the context). What this tells you is that you start with a monad m with a type a, you give it a function that works with an a and returns a monad m with a type mb, and bind will give you back that last m b.
To illustrate it a bit better, if I have a value x and I apply it a function a -> m b, like something that returns a Maybe b, and I want to apply that a -> m b again, I would end up with Maybe (Maybe b). bind lets you do composition while avoiding that nesting.
fmap on the other hand is a way to lift a function to work in a context. Itβs signature is fmap :: (a -> b) -> (f a -> f b), which means that you start with a function from a to b and get back a lifted function that works in a context f(the functor). This is essentially what you do with Enum.map, you give it an list and it takes care of using the function in every element of the list and returns back a list. If you have a Maybe, fmap would lift the function to be applied to the element inside the Just but skip the Nothing.
Monads are indeed Functors in the sense that you can define fmap in terms of bind and return(the functions in that monadex module):
fmap f m = m >>= (return . f)
The other altenative is defining bind in terms of join and fmap.
The definition of fmap doesnβt involve monads though, itβs just a way to lift a function to work in a particular context.
An fmap definition for a result tuple would look like this:
def fmap({:ok, x}, f) do
{:ok, f.(x)}
end
def fmap({:error, x}, _) do
{:error, x}
end
While a definition of bind would looke like this:
def bind({:ok, x}, f) do
f.(x)
end
def bind({:error, x}, _) do
{:error, x}
end
Notice that in fmap we extract the x from the tuple so it can work with f (the a -> f a lifting), and then it wraps the result of applying f to x in an ok tuple again (the b -> f b lifting), essentially making the function f work in the context of a result tuple. But in bind the f already returns a result tuple, so we donβt need to wrap it, otherwise it would result in nested result tuples.
More βcorrectβ definitions would be curried functions, though, so fmap would be:
def fmap(f), do: fn
{:ok, x} -> {:ok, f.(x)}
{:error, x} -> {:error, x}
end
So fmap here returns a version of f that can work with result tuples. I think this is a better illustration of what lifting a function means.