0
votes

I am struggling to understand function within function signature types in Haskell, I have seen this function;

twice :: (a -> a) -> a -> a
twice f x = f(f x)

Which does twice the chosen function on a parameter. I understand f is a function however do not understand why we have the signature type (a -> a) -> a -> a I thought it would be (a -> b) -> a -> b because

  1. You provide a as a parameter so the input of the function must accept the type of a.
  2. b is the output type of the function so the overall output type is of type b.

I am new to Haskell :)

2
if it was a -> b you could not apply the function for a second time, because after the first time you will have type b, but your function only takes a as an input argbehzad.nouri
Okay that makes sense so that's why it's all as for the type signaturesdijam

2 Answers

4
votes

Let's see what happens!

twice :: (a -> b) -> a -> b
twice f x = f (f x)

Just reading the type of twice, we immediately know:

f :: a -> b
x :: a

Therefore:

f x :: b

If f :: a -> b and f x :: b, what is the type of f (f x)? We do not know if a = b, so we do not know if we can apply f x to f. If we don't know then we cannot safely compile the program.

Couldn't match expected type `a' with actual type `b'
...
In the first argument of `f', namely `(f x)'
In the expression: f (f x)
0
votes

You are right, the function's type can also be written in the more general form (a -> b) -> a -> b. However, you get a slight problem with f (f x) then: the result of f x is b, but the outer f expects its argument to have type a. So a and b must actually be the same type! You could write this as

twice :: (a~b) => (a -> b) -> a -> b

where a~b is an equality constraint (you need one of the GHC extensions TypeFamilies or GATDs so this is accepted). But if both are the same type anyway, you might as well give them the same name right away... for example, a. This simplifies the signature to

twice :: (a -> a) -> a -> a