Working through the Haskell Book and my brain is breaking on the following example. I really don't know what the flip function is doing on line 21
1 class Functor f where
2 fmap :: (a -> b) -> f a -> f b
3
4 class Functor f => Applicative f where
5 pure :: a -> f a
6 (<*>) :: f (a -> b) -> f a -> f b
7
8 class Applicative f => Monad f where
9 return :: a -> f a
10 (>>=) :: f a -> (a -> f b) -> f b
11
12 instance Functor ((->) r) where
13 fmap = (.)
14
15 instance Applicative ((->) r) where
16 pure = const
17 f <*> a = \r -> f r (a r)
18
19 instance Monad ((->) r ) where
20 return = pure
21 ra >>= arb = flip arb <*> ra
-- flip :: (a -> b -> c) -> b -> a -> c
-- ra >>= arb = flip arb <*> ra
As I understand it, flip takes a function that takes two arguments, then two individual arguments, and returns a value. In the bind example, are we passing arb as the (a -> b -> c), then <*> as the b in flip's signature, and finally ra as the a? I can't see it.
I've tried making the types more specific to my actual example so you could rewrite <*> as
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
and I can do the same for bind
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
so even a dummy like myself can see that if we could swap <*> around
we could line then up like
(<???>) :: (r -> a) -> (r -> a -> b) -> (r -> b)
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
but looking at the second arguments there, the first one wants an r as its first argument and bind wants an a
So somehow flip is the book's example is doing that for us, but I really don't understand how. Any help would be greatly appreciated.
Thank you!
Top-level point of confusion, I think: flip is modifying arb, not modifying <*> as you seem to believe. We have "modified" <*> to have the "right" argument order just by giving <*> its arguments in the opposite order we got them!
Now for the details. We have, as you noted:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
So, since we have on the left hand side written
ra >>= arb = ...
then what we have in scope is:
ra :: r -> a
arb :: a -> r -> b
(Note how the names were chosen to reflect the types!) Rewriting the type you gave for flip, we have
flip :: (a -> b -> c) -> b -> a -> c -- original
flip :: (a -> r -> b) -> r -> a -> b -- rename variables
hence:
flip arb :: r -> a -> b
Now recall the type of (<*>) that you wrote:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
So for the first argument to (<*>), we want something of type r -> a -> b. Hey! flip arb has that type! For the second argument, we want something of type r -> a. And we're in luck again, because ra has that type, so...
flip arb <*> ra :: r -> b
(As usual with infix operators, this is the application of the operator (<*>) the arguments flip arb and ra.) What type were we hoping to have? Well, we go back to the type of (>>=) now:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
After taking two arguments, this is supposed to return something of type r -> b. Cool, that's what we have built.
ra >>= arb = flip arb <*> ra
Related
I've begun reading the book Thinking With Types which is my first foray into type level programming. The author provides an exercise and the solution, and I cannot understand how the solution provided is correct.
The exercise is
I attempted to solve this exercise with the following
productToRuleMine :: (b -> a, c -> a) -> Either b c -> a
productToRuleMine (f, _) (Left b) = f b
productToRuleMine (_, g) (Right c) = g c
productFromRuleMine :: (Either b c -> a) -> (b -> a, c -> a)
productFromRuleMine f = (f . Left, f . Right)
productToRuleMine . productFromRuleMine = id
I feel this is a valid solution, however the book gives a different solution that doesn't seem to type check, leading me to believe my overall understanding is flawed
productToRuleBooks :: (b -> a) -> (c -> a) -> (Either b c) -> a
productToRuleBooks f _ (Left b) = f b
productToRuleBooks _ g (Right c) = g c
productFromRuleBooks :: (Either b c -> a) -> (b -> a, c -> a)
productFromRuleBooks f = (f . Left, f . Right)
The only way I can get the books answer to type check is the following:
(uncurry productToRule1 . productFromRule1) = id
since the type signatures alone don't line up
(Either b c -> a) -> (b -> a , c -> a)
(b -> a) -> (c -> a) -> (Either b c) -> a
So the question I have is, is my solution incorrect? Why does the books type signature for productToRuleBooks accept as it's first and second arguments the functions b -> a and c -> a when it's my understanding that x (multiplication) from algebra equates to the (,) in types, so why doesn't the books answer have (b -> a, c -> a) as the first argument?
I wonder whether there is a good name for functions with the following signature and implementation (Haskell-notation):
humble :: (a -> a -> b) -> a -> b
humble f x = f x x
It seems somehow related to fold1 (fold with no base case).
As has been mentioned by #4castle in the comments, the function you're looking for is join in Control.Monad. It's type is
join :: Monad m => m (m a) -> m a
The simple reader monad is (->) r,so if we set m ~ (->) r, we get
join :: (->) r ((->) r a) -> (->) r a
or, more concisely,
join :: (r -> r -> a) -> (r -> a)
which is what you want.
According to the tutorial on Lenses:
type Getting b a b = (b -> Const b b) -> (a -> Const b a)
-- ... equivalent to: (b -> b ) -> (a -> b )
-- ... equivalent to: (a -> b )
Question: Why is (b -> b) -> (a -> b) equivalent to (a -> b)?
The tutorial isn't very precise about this. Here's the full definition of Getting:
type Getting r s a = (a -> Const r a) -> s -> Const r s
Stripping off the newtype noise,
Getting r s a ~= (a -> r) -> s -> r
The interesting isomorphism you should get from this is the following:
(forall r. Getting r s a) ~= s -> a
In a now-deleted comment, chi pointed out that this is a special case of the Yoneda lemma.
The isomorphism is witnessed by
fromGetting :: Getting a s a -> (s -> a)
fromGetting g = getConst . g Const
-- ~= g id
-- Note that the type of fromGetting is a harmless generalization of
-- fromGetting :: (forall r. Getting r s a) -> (s -> a)
toGetting :: (s -> a) -> Getting r s a
toGetting f g = Const . getConst . g . f
-- ~= g . f
-- Note that you can read the signature of toGetting as
-- toGetting :: (s -> a) -> (forall r. Getting r s a)
Neither fromGetting nor toGetting has a rank-2 type, but to describe the isomorphism, the forall is essential. Why is this an isomorphism?.
One side is easy: ignoring the Const noise,
fromGetting (toGetting f)
= toGetting f id
= id . f
= f
The other side is trickier.
toGetting (fromGetting f)
= toGetting (f id)
= \g -> toGetting (f id) g
= \g -> g . f id
Why is this equivalent to f? The forall is the key here:
f :: forall r. Getting r s a
-- forall r. (a -> r) -> s -> r
f has no way to produce an r except by applying the passed function (let's call it p) to a value of type a. It's given nothing but p and a value of type s. So f really can't do anything except extract an a from the s and apply p to the result. That is, f p must "factor" into the composition of two functions:
f p = p . h
So
g . f id = g . (id . h) = g . h = f g
The type says "You give me a b -> b and an a, and I'll give you a b." What can a function with that type do with its b -> b? Two options:
Ignore the function altogether
Apply it to a b
How do you get hold of a b to apply the function to? You use the a to produce one. So either way, it has to do the work of an a -> b.
Here's some code to witness the (edit: not-quite) isomorphism.
in :: ((b -> b) -> a -> b) -> (a -> b)
in f x = f id x
out :: (a -> b) -> ((b -> b) -> a -> b)
out f g x = g (f x)
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)
I'm trying to understand the <=< function:
ghci> :t (<=<)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
As I understand it, I give it 2 functions and an a, and then I'll get an m c.
So, why doesn't this example compile?
import Control.Monad
f :: a -> Maybe a
f = \x -> Just x
g :: a -> [a]
g = \x -> [x]
foo :: Monad m => a -> m c
foo x = f <=< g x
For foo 3, I would expect Just 3 as a result.
But I get this error:
File.hs:10:15:
Couldn't match expected type `a0 -> Maybe c0'
with actual type `[a]'
In the return type of a call of `g'
Probable cause: `g' is applied to too many arguments
In the second argument of `(<=<)', namely `g x'
In the expression: f <=< g x Failed, modules loaded: none.
There are two errors here.
First, (<=<) only composes monadic functions if they share the same monad. In other words, you can use it to compose two Maybe functions:
(<=<) :: (b -> Maybe c) -> (a -> Maybe b) -> (a -> Maybe c)
... or two list functions:
(<=<) :: (b -> [c]) -> (a -> [b]) -> (a -> [c])
... but you cannot compose a list function and maybe function this way. The reason for this is that when you have a type signature like this:
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
... the compiler will ensure that all the ms must match.
The second error is that you forgot to parenthesize your composition. What you probably intended was this:
(f <=< g) x
... if you omit the parentheses the compiler interprets it like this:
f <=< (g x)
An easy way to fix your function is just to define a helper function that converts Maybes to lists:
maybeToList :: Maybe a -> [a]
maybeToList Nothing = []
maybeToList (Just a) = [a]
This function actually has the following two nice properties:
maybeToList . return = return
maybeToList . (f <=< g) = (maybeToList . f) <=< (maybeToList . g)
... which are functor laws if you treat (maybeToList .) as analogous to fmap and treat (<=<) as analogous to (.) and return as analogous to id.
Then the solution becomes:
(maybeToList . f <=< g) x
Note that, in
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
m is static -- You're trying to substitute both [] and Maybe for m in the definition -- that won't type check.
You can use <=< to compose functions of the form a -> m b where m is a single monad. Note that you can use different type arguments though, you don't need to be constrained to the polymorphic a.
Here's an example of using this pattern constrained to the list monad:
f :: Int -> [Int]
f x = [x, x^2]
g :: Int -> [String]
g 0 = []
g x = [show x]
λ> :t g <=< f
g <=< f :: Int -> [String]
λ> g <=< f $ 10
["10","100"]
You can't mix monads together. When you see the signature
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
The Monad m is only a single Monad, not two different ones. If it were, the signature would be something like
(<=<) :: (Monad m1, Monad m2) => (b -> m2 c) -> (a -> m1 b) -> a -> m2 c
But this is not the case, and in fact would not really be possible in general. You can do something like
f :: Int -> Maybe Int
f 0 = Just 0
f _ = Nothing
g :: Int -> Maybe Int
g x = if even x then Just x else Nothing
h :: Int -> Maybe Int
h = f <=< g