In Haskell, what does the monad instance of functions give over just applicative? Looking at their implementations, they seem almost identical:
(<*>) f g x = f x (g x)
(>>=) f g x = g (f x) x
Is there anything you can do with >>= that you can't do with just <*>?
They are equivalent in power for the function instance: flip f <*> g == g >>= f. This is not true for most types that are instances of Monad though.
It's a little more clear if we compare <*> and =<< (which is flip (>>=)) specialized to the ((->) r) instance:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
-- Specialized to ((->) r):
(<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
(=<<) :: Monad m => (a -> m b) -> m a -> m b
-- Specialized to ((->) r):
(=<<) :: (a -> r -> b) -> (r -> a) -> r -> b
Related
I'm new to Monads and was trying to write an add function and I'm unsure why this doesn't work. When using monads, is there a specific way you need to return a value?
monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= (\y -> (x + y)))
You want to use pure (more general form of return)
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
The right-hand side (continuation) of >>= must always return a monadic action. But when you add x + y :: a you have a number. You need pure (x + y) :: m a to turn it into a monadic action:
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
^^^ ^ ^^^ ^ ^^^^^^^^^^^^
m a a m a a m a
You can equivalently write it in do-notation
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = do
x <- mx
y <- my
pure (x + y)
Actually. This doesn't require Monad. Applicative (n-ary lifting) is sufficient:
monadd :: Applicative m => Num a => m a -> m a -> m a
monadd = liftA2 (+)
Reminder that Functor lifts a unary function and Applicative lifts constants and n-ary functions (where liftA0 = pure and liftF1 = fmap):
liftA0 :: Applicative f => (a) -> (f a)
liftF1 :: Functor f => (a -> b) -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c) -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)
You only need Monad when there is a dependency between the computations. Notice that in your case the my computation does not dependent on the result of the mx computation.
If m b depended on the output of m a it would become a -> m b. Then Monad is required:
dependency :: Monad m => (a -> b -> c) -> m a -> (a -> m b) -> m c
dependency (·) as bs = do
a <- as
b <- bs a
pure (a · b)
When using monads, is there a specific way you need to Return a value?
Yes, you will need to wrap x and y back in a monadic context, with return :: Monad m => a -> m a, so:
monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= return (x+y)))
Since the two operations of the monad mx and my operate independently of each other however, Applicative is sufficient, you can implement this as:
monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd mx my = (+) <$> mx <*> my
or through liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c:
monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd = liftA2 (+)
I'm told the following functions are equivalent in power
hylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b
hylo f g = h where h = f . fmap h . g
hyloM :: (Traversable g, Monad m) => (g b -> m b) -> (a -> m (g a)) -> a -> m b
hyloM f g = h where h = f <=< traverse h <=< g
For the life of me, though, I can't figure out how to demonstrate this. Setting Monad to Identity in hyloM gets pretty much the right thing, but g is Traversable not Functor, and I have tried a number of approaches to go from hylo to hyloM with no success.
Are these isomorphic, or at least similar in power? If so, how do I evidence that?
You can define hyloM using hylo by instantiating f = Compose m g.
hyloM' :: (Traversable g, Monad m) => (g b -> m b) -> (a -> m (g a)) -> a -> m b
hyloM' f g = hylo (\(Compose mg) -> mg >>= sequence >>= f) (\a -> Compose (g a))
I'm not sure about the converse.
a line from FileIO.hs in Functional Programming Course exercise
getFile :: FilePath -> IO (FilePath, Chars)
getFile = lift2 (<$>) (,) readFile
According to its type signature, getFile returns IO ( FilePath, Chars), which means a tuple of filename and its content.
But I just can't figure out why it turns that way.
Why does FilePath turn out unchanged in the left, and readFile filename filled in the right?
Is (,) an Applicative instance too? (,) is not an IO, so what did lift2 lift?
And, is there a way to derive those type signatures and get proved?
The syntax I know is that a function follows by its arguments, and it eats one argument on its right hand and becomes a new function. But when it comes to code like that, it looks just like a magic cube to me...
Thank you for helping me out!
Ps. Extra Information as follows
instance Functor IO where
(<$>) =
P.fmap
lift2 ::
Applicative f =>
(a -> b -> c)
-> f a
-> f b
-> f c
lift2 f a b =
f <$> a <*> b
getFiles :: List FilePath -> IO (List (FilePath, Chars))
getFiles = sequence . (<$>) getFile
Let's look at
lift2 (<$>) (,) readFile
This is indeed straightforward function application:
((lift2 (<$>)) (,)) readFile
(or lift2 being applied to three arguments).
The types involved (with uniquely renamed type variables to reduce confusion) are:
lift2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
(<$>) :: (Functor g) => (j -> k) -> g j -> g k
(,) :: m -> n -> (m, n)
readFile :: FilePath -> IO Chars
The first thing in our expression is applying lift2 to (<$>). That means we need to unify a -> b -> c (type of lift2's first argument) and (Functor g) => (j -> k) -> g j -> g k (type of <$>) somehow.
That is:
a -> b -> c = (j -> k) -> g j -> g k
-- where g is a Functor
a = j -> k
b = g j
c = g k
This works out. The result type is
f a -> f b -> f c
-- where f is an Applicative
which is
f (j -> k) -> f (g j) -> f (g k)
Now this expression (lift2 (<$>)) is applied to (,). Again we have to make the types line up:
f (j -> k) = m -> n -> (m, n)
Here we make use of the property that -> is right associative (i.e. a -> b -> c means a -> (b -> c)) and that we can use (curried) prefix notation in types (i.e. a -> b is the same as (->) a b, which is the same as ((->) a) b).
f (j -> k) = ((->) m) (n -> (m, n))
f = (->) m
j = n
k = (m, n)
This also works out. The result type is
f (g j) -> f (g k)
which (after substituting) becomes
((->) m) (g n) -> ((->) m) (g (m, n))
(m -> g n) -> (m -> g (m, n))
This expression (lift2 (<$>) (,)) is applied to readFile. Again, making the types line up:
m -> g n = FilePath -> IO Chars
m = FilePath
g = IO
n = Chars
And substituting into the result type:
m -> g (m, n)
FilePath -> IO (FilePath, Chars)
This is the type of the whole lift2 (<$>) (,) readFile expression. As expected, it matches the declaration of getFile :: FilePath -> IO (FilePath, Chars).
However, we still need to verify that our class constraints (Functor g, Applicative f) are resolved.
g is IO, which is indeed a Functor (as well as Applicative and Monad). There are no big surprises here.
f is more interesting: f = (->) m, so we need to look for an Applicative instance for (->) m. Such an instance does in fact exist, and its definition contains the answer to what getFile actually does.
We can derive what the instance must look like by just looking at the type of lift2 (as used in getFile):
lift2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
lift2 :: (a -> b -> c) -> ((->) m) a -> ((->) m) b -> ((->) m) c
lift2 :: (a -> b -> c) -> (m -> a) -> (m -> b) -> (m -> c)
lift2 :: (a -> b -> c) -> (m -> a) -> (m -> b) -> m -> c
I.e. lift2 takes
a function that combines an a and a b into a c,
a function that transforms an m into an a,
a function that transforms an m into a b,
and an m,
and produces a c.
The only way it can do that is by passing the m into the second and third functions and combining their results using the first function:
lift2 f g h x = f (g x) (h x)
If we inline this definition in getFile, we get
getFile = lift2 (<$>) (,) readFile
getFile = \x -> (<$>) ((,) x) (readFile x)
getFile = \x -> (,) x <$> readFile x
Excercise for the reader:
lift2 is actually defined in terms of <$> and <*>. What are the types of <$> and <*> in the Applicative instance of (->) m? What must their definition look like?
I have stumbled on this piece of code fold ((,) <$> sum <*> product) with type signature :: (Foldable t, Num a) => t a -> (a, a) and I got completely lost.
I know what it does, but I don't know how. So I tried to break it into little pieces in ghci:
λ: :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
λ: :t (,)
(,) :: a -> b -> (a, b)
λ: :t sum
sum :: (Foldable t, Num a) => t a -> a
Everything is okay, just basic stuff.
λ: :t (,) <$> sum
(,) <$> sum :: (Foldable t, Num a) => t a -> b -> (a, b)
And I am lost again...
I see that there is some magic happening that turns t a -> a into f a but how it is done is mystery to me. (sum is not even instance of Functor!)
I have always thought that f a is some kind of box f that contains a but it looks like the meaning is much deeper.
The functor f in your example is the so-called "reader functor", which is defined like this:
newtype Reader r = Reader (r -> a)
Of course, in Haskell, this is implemented natively for functions, so there is no wrapping or unwrapping at runtime.
The corresponding Functor and Applicative instances look like this:
instance Functor f where
fmap :: (a -> b) -> (r -> a)_-> (r -> b)
fmap f g = \x -> f (g x) -- or: fmap = (.)
instance Applicative f where
pure :: a -> (r -> a) -- or: a -> r -> a
pure x = \y -> x -- or: pure = const
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
frab <*> fra = \r -> frab r (fra r)
In a way, the reader functor is a "box" too, like all the other functors, having a context r which produces a type a.
So let's look at (,) <$> sum:
:t (,) :: a -> b -> (a, b)
:t fmap :: (d -> e) -> (c -> d) -> (c -> e)
:t sum :: Foldable t, Num f => t f -> f
We can now specialize the d type to a ~ f, e to b -> (a, b) and c to t f. Now we get:
:t (<$>) -- spcialized for your case
:: Foldable t, Num f => (a -> (b -> (a, b))) -> (t f -> f) -> (t f -> (b -> (a, b)))
:: Foldable t, Num f => (f -> b -> (f, b)) -> (t f -> f) -> (t f -> b -> (f, b))
Applying the functions:
:t (,) <$> sum
:: Foldable t, Num f => (t f -> b -> (f, b))
Which is exactly what ghc says.
The short answer is that f ~ (->) (t a). To see why, just rearrange the type signature for sum slightly, using -> as a prefix operator instead of an infix operator.
sum :: (Foldable t, Num a) => (->) (t a) a
~~~~~~~~~~
f
In general, (->) r is a functor for any argument type r.
instance Functor ((->) r) where
fmap = (.)
It's easy to show that (.) is the only possible implementation for fmap here by plugging ((->) r) into the type of fmap for f:
fmap :: (a -> b) -> f a -> f b
:: (a -> b) -> ((->) r) a -> ((->) r) b
:: (a -> b) -> (r -> a) -> (r -> b)
This is the type signature for composition, and composition is the unique function that has this type signature.
Since Data.Functor defines <$> as an infix version of fmap, we have
(,) <$> sum == fmap (,) sum
== (.) (,) sum
From here, it is a relatively simple, though tedious, job of confirming that the resulting type is, indeed, (Foldable t, Num a) => t a -> b -> (a, b). We have
(b' -> c') -> (a' -> b') -> (a' -> c') -- composition
b' -> c' ~ a -> b -> (a,b) -- first argument (,)
a' -> b' ~ t n -> n -- second argument sum
----------------------------------------------------------------
a' ~ t n
b' ~ a ~ n
c' ~ a -> b -> (a,b)
----------------------------------------------------------------
a' -> c' ~ t a -> b -> (a,b)
Applicative's has the (<*>) function:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
Learn You a Haskell shows the following function.
Given:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap f m = do
g <- f -- '<-' extracts f's (a -> b) from m (a -> b)
m2 <- m -- '<-' extracts a from m a
return (g m2) -- g m2 has type `b` and return makes it a Monad
How could ap be written with bind alone, i.e. >>=?
I'm not sure how to extract the (a -> b) from m (a -> b). Perhaps once I understand how <- works in do notation, I'll understand the answer to my above question.
How could ap be written with bind alone, i.e. >>= ?
This is one sample implementation I can come up with:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap xs a = xs >>= (\f -> liftM f a)
Of if you don't want to even use liftM then:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf ma = mf >>= (\f -> ma >>= (\a' -> return $ f a'))
Intially these are the types:
mf :: m (a -> b)
ma :: m a
Now, when you apply bind (>>=) operator to mf: mf >>= (\f-> ..., then f has the type of:
f :: (a -> b)
In the next step, ma is also applied with >>=: ma >>= (\a'-> ..., here a' has the type of:
a' :: a
So, now when you apply f a', you get the type b from that because:
f :: (a -> b)
a' :: a
f a' :: b
And you apply return over f a' which will wrap it with the monadic layer and hence the final type you get will be:
return (f a') :: m b
And hence everything typechecks.