Question

Consider:

:type (flip .)

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

I just can't figure out why. As I understand, flip has the following type:

flip :: (a -> b -> c) -> b -> a -> c

In addition (.) has the following type:

(.) :: (b1 -> c1) -> (a1 -> b1) -> a1 -> c1

Hence, unifying the types I get:

a = (b1 -> c1) -> (a1 -> b1)
b = a1

Which gives:

(flip .) :: a1 -> ((b1 -> c1) -> (a1 -> b1)) -> c1

Which is far from the actual type.

What am I doing wrong? Any sort of help would be appreciated.

Était-ce utile?

La solution

Consider the type of flip and function composition:

flip :: (a -> b -> c) -> b -> a -> c

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

Now you can either apply (.) to flip or else apply flip to (.).

In the first case:

(flip .)

-- is the same as

(.) flip

-- i.e. you are applying (.) to flip

Hence you get:

flip :: (a -> b -> c) -> b -> a -> c
        |___________|   |___________|
              |               |
(.) ::        b               c       -> (a -> b) -> a -> c

-- Hence:

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

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

In the second case:

(flip (.))

-- is the same as

flip (.)

-- i.e. you are applying flip to (.)

Hence you get:

(.) :: (b -> c) -> (a -> b) -> a -> c
       |______|    |______|   |______|
          |           |          |
flip ::   a           b          c     -> b -> a -> c

-- Hence:

(flip (.)) :: (a -> b) -> (b -> c) -> a -> c

flip (.) :: (a -> b) -> (b -> c) -> a -> c

The problem is that when you write (flip .) Haskell assumes that it is a section. Hence it considers flip as an argument since . is an operator. To treat an operator as a function you need to parenthesize it. Hence (flip (.)) is treated as applying flip to (.). In this case the extra set of parentheses are not required. You can simply write it as flip (.).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top