4

I'm trying to understand applicatives in Haskell. Can't figure out what does following type signature mean:

f (a -> b)

For example:

foo :: Num a => Maybe (a -> a)
foo = Just (+1)

How can I understand the meaning of Maybe (a -> a)? Is it a function? If it is, which types of arguments are allowed? Also obviously I'm new in functional programming, will be grateful for any resources on this topic.

duplode
  • 33,731
  • 7
  • 79
  • 150
wspbr
  • 137
  • 4
  • 5
    Do you know what `Maybe a` means? If you know that, and what `a -> a` means, just put them together. – Robin Zigmond Apr 20 '20 at 20:54
  • 1
    Well it is a `Just` data constructor that wraps (has as parameter) a *function* with type `Num a => a -> a`. In Haskell functions are "first class citizens". You can use functions as parameters, return functions, etc. Here it thus wraps a function that takes a number as parameter, and returns `1 +` that number. – Willem Van Onsem Apr 20 '20 at 20:55
  • Yeah, It's clear for me, I can't just understand how can I use it in this particular example. – wspbr Apr 20 '20 at 20:56
  • 1
    Well `f (a -> b)` is called an Applicative Functor. A function in a context like `Just (+1)`. You may use the applicative operator `<*>` to operate it among the same context values like `Just (+1) <*> Just 2` and the result would be ... `Just 3`. – Redu Apr 20 '20 at 21:06
  • 1
    for the resources, check out https://stackoverflow.com/tags/haskell/info... – Will Ness Apr 21 '20 at 11:20

2 Answers2

4

In functional programming, functions are not so different from numbers or any other kind of value. Really the only difference is that the way you use a function is by applying it to an argument.

A value of type Maybe a is either the value Nothing or it is Just x, where x is of type a. So if you have a value of type Maybe (a -> a), like your foo, it is either Nothing, or it is Just f where f is a function a -> a. In the least fancy way, you would use it like this:

case foo of
    Nothing -> "There was no function"
    Just f -> "There was a function, and its value at 0 is " ++ show (f 0)

So if it turns out that foo is not Nothing, then it contains Just a function as its value.


@Erich is right that especially the literal expression f (a -> b) is likely to be related to applicative functors, but that is not necessarily so. For example, a favorite type of mine is the type of isomorphisms -- equivalences between two types:

data Iso a b = Iso (a -> b) (b -> a)

Iso isn't even a Functor (a prerequisite of Applicative), but it is still quite useful. It turns out that pairs are equivalent to functions from Bool. We could construct such an equivalence as an Iso value:

pairEquiv :: Iso (a,a) (Bool -> a)
pairEquiv = 
    Iso (\(x,y) -> \b -> if b then x else y) -- from pair to function
        (\f -> (f True, f False))            -- from function to pair

Here (Bool -> a) appears as an argument to a type constructor, and it just means that if you give the Iso a pair, it will give you a function back, and vice versa.

luqui
  • 59,485
  • 12
  • 145
  • 204
2

You can imagine f (a -> b) as a function of type a -> b wrapped in a context. It is mostly used in the context of Applicatives, that Maybe a is a prominent example for.

Applicatives are an extension of Functors. A typical example for using Applicatives are functions with multiple arguments.

What if we have two Maybe Ints that we want to add up. We could try by partially applying + with fmap aka <$>. Thus we might try:

f :: Maybe (Int -> Int)
f = (+) <$> Just 3

But now, how do we apply this to a second argument. That's where we need the Applicative typeclass. It defines the <*> function. It has the type

<*> :: Applicative f => f (a -> b) -> f a -> f b

Thus we can use it to apply a second Maybe Int to our partially applied function f by doing:

> f <*> Just 4
Just 7

Without the helper function f the syntax resembles standard function application:

> (+) <$> Just 3 <*> Just 4
Just 7

For further reference see the chapter on applicative functors of learnyouahaskell.

Erich
  • 1,838
  • 16
  • 20
  • 3
    I think this answer is potentially misleading - while `Maybe` has an `Applicative` instance, that doesn't mean `f (a -> b)` for some arbitrary type constructor `f` is necessarily applicative. – Lee Apr 20 '20 at 21:22