I understand the advantage of IO monad and List Monad over Functor, however, I don't understand the advantage of Option/Maybe Monad over Functor.
Is that simply the integration of types of the language?
or
What is the advantage of Option/Maybe Monad over Functor in specific use?
PS. asking the advantage in specific use is not opinion-based because if there is, it can be pointed out without subjective aspect.
PS.PS. some member here is so eager to push repeatedly
Option is both a functor and a monad?
should be the answer, or QA is duplicate, but actually not.
I already know the basics such as
Every monad is an applicative functor and every applicative functor is a functor
as the accepted answer there, and that is not what I'm not asking here.
Having an excellent answer here that is Not included in the previous QA.
The aspect, detail, or resolution of each question is quite different, so please avoid "bundling" different things in rough manner here.
Let's look at the types.
fmap :: Functor f => (a -> b) -> (f a -> f b)
(<*>) :: Applicative f => f (a -> b) -> (f a -> f b)
flip (>>=) :: Monad f => (a -> f b) -> (f a -> f b)
For a functor, we can apply an ordinary function a -> b to a value of type f a to get a value of type f b. The function never gets a say in what happens to the f part, only the inside. Thinking of functors as sort of box-like things, the function in fmap never sees the box itself, just the inside, and the value gets taken out and put back into the exact same box it started at.
An applicative functor is slightly more powerful. Now, we have a function which is also in a box. So the function gets a say in the f part, in a limited sense. The function and the input each have f parts (which are independent of each other) which get combined into the result.
A monad is even more powerful. Now, the function does not, a priori, have an f part. The function takes a value and produces a new box. Whereas in the Applicative case, our function's box and our value's box were independent, in the Monad case, the function's box can depend on the input value.
Now, what's all this mean? You've asked me to focus on Maybe, so let's talk about Maybe in the concrete.
fmap :: (a -> b) -> (Maybe a -> Maybe b)
(<*>) :: Maybe (a -> b) -> (Maybe a -> Maybe b)
flip (>>=) :: (a -> Maybe b) -> (Maybe a -> Maybe b)
As a reminder, Maybe looks like this.
data Maybe a = Nothing | Just a
A Maybe a is a value which may or may not exist. From a functor perspective, we'll generally think of Nothing as some form of failure and Just a as a successful result of type a.
Starting with fmap, the Functor instance for Maybe allows us to apply a function to the inside of the Maybe, if one exists. The function gets no say over the success or failure of the operation: A failed Maybe (i.e. a Nothing) must remain failed, and a successful one must remain successful (obviously, we're glossing over undefined and other denotational semantic issues here; I'm assuming that the only way a function can fail is with Nothing).
Now (<*>), the applicative operator, takes a Maybe (a -> b) and a Maybe a. Either of those two might have failed. If either of them did, then the result is Nothing, and only if the two both succeeded do we get a Just as our result. This allows us to curry operations. Concretely, if I have a function of the form g :: a -> b -> c and I have values ma :: Maybe a and mb :: Maybe b, then we might want to apply g to ma and mb. But when we start to do that, we have a problem.
fmap g ma :: Maybe (b -> c)
Now we've got a function that may or may not exist. We can't fmap that over mb, because a nonexistent function (a Nothing) can't be an argument to fmap. The problem is that we have two independent Maybe values (ma and mb in our example) which are fighting, in some sense, for control. The result should only exist if both are Just. Otherwise, the result should be Nothing. It's sort of a Boolean "and" operation, in that if any of the intermediates fail, then the whole calculation fails. (Note: If you're looking for a Boolean "or", where any individual success can recover from prior failure, then you're looking for Alternative)
So we write
(fmap g ma) <*> mb :: Maybe c
or, using the more convenient synonym Haskell provides for this purpose,
g <$> ma <*> mb :: Maybe c
Now, the key word in the above situation is independent. ma and mb have no say over the other's success or failure. This is good in many cases, because code like this can often be parallelized (there are very efficient command line argument parsing libraries that exploit just this property of Applicative). But, obviously, it's not always what we want.
Enter Monad. In the Maybe monad, the provided function produces a value of type Maybe b based on the input a. The Maybe part of the a and of the b are no longer independent: the latter can depend directly on the former.
For example, take the classic example of Maybe: a square root function. We can't take a square root of a negative number (let's assume we're not working with complex numbers here), so our hypothetical square root looks like
sqrt :: Double -> Maybe Double
sqrt x | x < 0 = Nothing
| otherwise = Just (Prelude.sqrt x)
Now, suppose we've got some number r. But r isn't just a number. It came from earlier in our computation, and our computation might have failed. Maybe it did a square root earlier, or tried to divide by zero, or something else entirely, but it did something that has some chance of producing a Nothing. So r is Maybe Double, and we want to take its square root.
Obviously, if r is already Nothing, then its square root is Nothing; we can't possibly take a square root if we've already failed to compute everything else. On the other hand, if r is a negative number, then sqrt is going to fail and produce Nothing despite the fact that r is itself Just. So what we really want is
case r of
Nothing -> Nothing
Just r' -> sqrt r'
And this is exactly what the Monad instance for Maybe does. That code is equivalent to
r >>= sqrt
The result of this entire computation (and, namely, whether or not it is Nothing or Just) depends not just on whether or not r is Nothing but also on r's actual value. Two different Just values of r can produce success or failure depending on what sqrt does. We can't do that with just a Functor, we can't even do that with Applicative. It takes a Monad.
I'm learning Purescript using the purescript-node-http library. If I have a value whose type is the following:
> :t f
forall t3.
Eff
( http :: HTTP
, console :: CONSOLE
| t3
)
Request
How would I be able to evaluate this in psci and assign the Request return value to a variable?
You can't bind the result to a variable right now. That feature might be supported in a later version. Note that you can evaluate the result and print it out.
If you use the browser as your evaluation environment (with --port) then one option is to store the result in a Ref and use the Ref later to retrieve the value.
The problem with the Node backend is that there is no persistent state, so that approach would not be possible at all with the Node backend.
In Database.MongoDB.Query, there is this function:
access :: MonadIO m => Pipe -> AccessMode -> Database -> Action m a -> m a
The documentation says this about the function:
Run action against database on server at other end of pipe. Use access mode for any reads and writes. Return Left on connection failure or read/write failure.
What does "return Left" mean here? I ask because m can be any monad (with a MonadIO instance). For instance, what does "return Left" mean if m is just the IO monad?
Must m be the Either monad for me to be able to detect connection or read/write failure when using the access method?
Yes. It's a type. Return Left comes from an older version. If any errors happens then it just throws IO exceptions. We'll need to fix it.
I filed a bug for it. https://github.com/mongodb-haskell/mongodb/issues/67
I find the Option Monad to be intuitive to understand, while List is not.
Some(1) >>= { x=>Some(x+1)}
Ma -> a -> Mb -> Mb
if I extract value from Some(1) I know it is 1
but in the list case
List(3,4,5) flatMap { x=> List(x,-x) }
if I extract value from List, what do I get ? how to make the understanding process intuitive
Intuition behind an Option or Maybe is actually very similar to List monad. The main difference is that List is non-deterministic - we don't know how many values we can get, when with Option it's always one on success and zero on failure. Empty list is considered a failure.
I think this piece describes it quite well:
For lists, monadic binding involves joining together a set of
calculations for each value in the list. When used with lists, the
signature of >>= becomes:
(>>=) :: [a] -> (a -> [b]) -> [b]
That is, given a list of a's and a function that maps an a onto a list
of b's, binding applies this function to each of the a's in the input
and returns all of the generated b's concatenated into a list.
And an example of list implementation:
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
fail _ = []
Sorry for putting Haskell into Scala answer, but that was the resource I used to understand this stuff.
Scala's flatMap is not exactly Haskell's bind >>=, but quite close to it. So what does it all mean?:
Imagine a practical situation where you have a list of clients List[Client], you can bind them to a single list of orders List[Order] that will be automatically flattened for you with flatMap or >>=. If you would use a map instead, you would get a List[List[Order]]. In practice you will provide the function for >>= to use, similarly how you provide a function to fold - you decide how data has to be generated/aggregated/etc. What bind does for you is to provide a general pattern for combining two monadic values and for each type of monads implementation will be unique.
You might prefer to look at it at as multiple levels of abstraction (from more general to less):
Monad has bind operation that will combine two monadic values into one: (>>=) :: m a -> (a -> m b) -> m b.
List as a monad instance implements bind with something like this: xs >>= f = concat (map f xs) - map the function over all elements and concatenate results into a single list.
You provide an implementation of the function f for the bind function depending on your needs (the clients -> orders example).
Once you know how bind behaves for your monad instances (List, Option) you can think in terms of just using it and "forget" about actual implementation.
I am just starting to learn Purescript so I hope that this is not a stupid question.
Suppose that we have an object
a = {x:1,y:2}
an we want to change x to equal 2. As far as I can see if we use the ST monad we will have to copy the whole object in order to change the value. If the initial object is big this would be very inefficient. What is the right way to mutate objects in place?
The ST monad is a fine approach, but depending on your use case, there may or may not be standard library functions for this.
The Data.StrMap module in purescript-maps defines a foreign type for homogeneous records with string keys, so if your values all have the same type, you could use Data.StrMap.ST to mutate your record in place.
If not, you should be easily able to define a function to update a record in place using ST and the FFI. The tricky bit is picking the right type. If you want to do something for a specific key, you could write a function
setFoo :: forall r a h eff. STRef h { foo :: a | r } -> a -> Eff (st :: ST h | eff) Unit
for example. Defining a generic setter would be more difficult without losing type safety. This is the trade-off made by Data.StrMap: you restrict yourself to a single value type, but get to use arbitrary keys.