Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand the function "(.)(.)" in Haskell

Tags:

types

haskell

I am a beginner in Haskell and I come across the function (.)(.), I use :t to get its type in GHCi:

:t (.)(.)
(.)(.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c

How to understand the type (.)(.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c here? I am very confused.

like image 901
zhangyunqi Avatar asked Aug 29 '16 13:08

zhangyunqi


People also ask

How are functions defined in Haskell?

The most basic way of defining a function in Haskell is to ``declare'' what it does. For example, we can write: double :: Int -> Int double n = 2*n. Here, the first line specifies the type of the function and the second line tells us how the output of double depends on its input.

What do you understand by higher order functions in Haskell?

Elementary HaskellA function that takes another function (or several functions) as an argument is called a higher-order function. They can be found pretty much anywhere in a Haskell program, and indeed we have already met some of them, such as map and the various folds.

How do you read a type in Haskell?

In Haskell read function is used to deal with strings, if you want to parse any string to any particular type than we can use read function from the Haskell programming. In Haskell read function is the in built function, that means we do not require to include or install any dependency for it, we can use it directly.

What does == mean in Haskell?

The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.


1 Answers

This is a partial application of the composition operator to the composition operator itself. In general, we know that if we apply (.) to some function f :: x -> y, then

>>> :t (.) f
(.) f :: (a -> x) -> a -> y

because of how the types line up:

(b -> c) -> (a -> b) -> a -> c
 x -> y
--------------------------------
            (a -> x) -> a -> y

We drop the first argument, and replace remaining occurrences of b and c with the corresponding types of the given argument.

Here, f is just (.) again, meaning we identify x ~ (b -> c) and y ~ (a -> b) -> a -> c. Lining up the types again

(a ->   x   )  -> a ->              y
      b -> c               (a -> b) -> a -> c

Since a occurs on the top and the bottom, we need to pick a new variable name for a on the bottom; GHC chose a1:

(a ->   x   )  -> a ->               y
      b -> c               (a1 -> b) -> a1 -> c

Putting the two together yields the type you see in GHCi.

(a -> b -> c) -> a -> (a1 -> b) -> a1 -> c

Anatomy jokes aside, what is (.)(.)?

Let's say you have a function f :: a -> b, but you want a function g :: a -> c, that is, you want f but with a different return type. The only thing you can do is find a helper function h :: b -> c that will convert the return value for you. Your function g is then simply the composition of h and f:

g = h . f

You might, however, have a more general function h' :: t -> b -> c, which can turn values of type b into values of type c in multiple ways, depending on the value of some argument x :: t. Then you could get lots of different gs depending on that argument.

g = (h' x) . f

Now, given h', x, and f, we can return our g, so let's write a function that does that: a function that "promotes" the return value of f from a value of type b to a value of type c, given a function h' and some value x:

promote h' x f = (h' x) . f

You can mechanically convert any function to point-free form; I'm not familiar with the details, but using PointFree.io produces

promote = ((.) .)

which is just the partial application (.) (.) written as a section, that is:

((.) (.)) h' x f == (h' x) . f

So, our "boobs" operator is just a generalized pre-composition operator.

like image 158
chepner Avatar answered Oct 03 '22 17:10

chepner