Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "f (a -> b)" type signature mean in Haskell?

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.

like image 954
wspbr Avatar asked Oct 15 '25 10:10

wspbr


2 Answers

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.

like image 73
luqui Avatar answered Oct 18 '25 22:10

luqui


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.

like image 30
Erich Avatar answered Oct 18 '25 23:10

Erich