Question on map . map sum

The lefthand fmap in [B] is instantiated to the ((->) [Integer]) functor.

The righthand fmap in [B] is instantiated to the Maybe functor.

Note that HLS gives both the general type of fmap, and the specific type, so it’s extremely useful for answering questions like the ones here.

  1. What does _ at the beginning of lines mean. Usually it is the wildcard placeholder but thinking of it that way here isn’t giving me any meaning.

  2. Can the general fmap with the specific type be lined-up?
    The first could be like this:

Which would mean that

(Maybe [Integer] -> Maybe Integer) -> ([Integer] -> Maybe [Integer])

is the `(a → b) but if so it would normally have an additional set of parens

((Maybe [Integer] -> Maybe Integer) -> ([Integer] -> Maybe [Integer]))

This also look like it might be right

Except that

Maybe [Integer]

Looks more like f (f a) then f a because both Maybe and [] are functors.


3. Could you shed some light on

forall (f :: * -> *) a b.

What does _ at the beginning of lines mean. Usually it is the wildcard placeholder but thinking of it that way here isn’t giving me any meaning.

i think it just means: the thing you moused over, which in this case was fmap.

Can the general fmap with the specific type be lined-up?

I don’t think what you showed is right.

The lefthand fmap, when lined up is:

(a                                ->    b).   ->                     ( f a                          ->                f b)
Maybe [Integer]                  Maybe Integer                       ( [Integer] -> Maybe [Integer])                 ([Integer] -> Maybe Integer  )

Your second screenshot is correct for the righthand fmap. I see your confusion, which is that it looks like f (g a), because both Maybe and [] are functors. But the crucial point is that a can be anything! In this case, a is [Integer] and b is Integer. So it’s indeed f a.

Could you shed some light on…

Yeah, it’s a more verbose way of writing things. In haskell, as you know, you can write universally quantified types like id :: a -> a, but you can also more explicitly write id :: forall a. a -> a. You can even explicitly specify the kind, as in: id :: forall (a :: *). a -> a. (This is more common in more recent GHC version, like 9).

In the type of fmap, which is, in full verbosity:

fmap :: forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b

you can read this as saying: for any three types f, a, and b, such that f has kind * -> *, and also such that f is an instance of the Functor class, fmap takes a function a -> b and gives you a function f a -> f b.

Addendum

Rather than the lining up, which is a bit hard to typeset, let me also use the following notation:

For the righthand fmap:

a ~ [Integer]
b ~ Integer
f ~ Maybe
(f a) ~ Maybe [Integer]
(f b) ~ Maybe Integer

For the lefthand fmap:

a ~ Maybe [Integer]
b ~ Maybe Integer
f ~ ( (->) [Integer]
(f a) ~ ([Integer] -> Maybe [Integer])
(f b) ~ ([Integer] -> Maybe Integer)

Hopefully that’s totally clear and non-ambiguous - let me know if not.

Yes, totally clear on what is what there.

Want to check my understanding …

So (->) [Integer] is ??

> :k (->)
(->) :: * -> * -> *
> :k (->) [Integer]
(->) [Integer] :: * -> *

And can thought of as ??

[Integer] -> * -> *

Does this help?

(+) 1 2 is the same as 1 + 2.
(->) String Int is the same as String -> Int.

Either has kind * -> * -> *, so it takes two types as parameters.
For example Either String Int is a type that is either a Left String or a Right Int.

(->) also has kind * -> * -> *, so it takes two types as parameters.
For example (->) String Int is a type that is a function from String to Int.

Either String has kind * -> *, so it needs one more type.
It makes a type that is either a Left String or a Right X, where X isn’t decided yet.

(->) String has kind * -> *, so it needs one more type.
It makes a type that is a function from String to X, where X isn’t decided yet.

1 Like

Thanks! As I read that the answer is “Yes”.

And can thought of as ??

This slightly confuses types and kinds. [Integer] is a type, but * is a kind, so [Integer] -> * -> * isn’t a well formed expression. But if you’re asking: is the first type input into (->) in this example [Integer], then yes, that’s right.

By the way, the Reader type is defined as:

newtype Reader a b = Reader (a -> b)

so it’s just a different name for the (->) a Functor. It comes up a lot because there’s also a monad instance, and people very commonly write code like:

example :: Reader Int (Bool, Int)
example = do
  x <- ask
  let y = x > 4
  return (y,x)

which happens to be a super useful way of passing around a global environment variable.

1 Like

How is this?

fmap :: (a -> b) -> (Int -> a) -> (Int -> b)
fmap fn1 fn2 =  fn1 . fn2

Is it valid to look like types like this?

If I look at

fmap (>3) (+1)

fmap           ::  Functor f                => (a -> b) -> f a -> f b     -- [A]
fmap (>3)      :: (Functor f, Ord a, Num a) =>             f a -> f Bool  -- [B]
fmap (>3) (+1) :: (           Ord a, Num a) =>               a ->   Bool  -- [C]

The change from [B] to [C] seems to say that (>3) (+1) form a functor.

((>3) . (+1)) :: (Ord b, Num b) => b -> Bool

And b -> Bool does meet the kind * -> * requirement of Functor

How is this?

Exactly! Or even just:

fmap = (.)

Satisfying, no?

to say that (>3) (+1) form a functor

Worth being a bit pedantic here. ((>3) . (+1)) is a value, not a type, so it doesn’t make sense to say it’s a Functor. It’s true that the type (->) b is a Functor though, as you say.

It should be:

fmap           ::  Functor f                => (a -> b) -> f a -> f      b     -- [A]
fmap (>3)      :: (Functor f, Ord a, Num a) =>             f a -> f      Bool  -- [B]
fmap (>3) (+1) :: (           Ord a, Num a) =>                    (->) a Bool  -- [C]

Every time you apply an argument one of the arrows disappear. Arrows can only reappear if you instantiate a polymorphic type variable to a type involving an arrow. In this case you instantiate f to (->) a.

It is satisfying. After I figured things out last night I quit for the day and enjoyed “brief” satisfaction. Now I’m on to the next frustration :slight_smile:

And you point about types vs values is a good one to keep thinking about.

1 Like