[Haskell-cafe] function composition

Daniel Fischer daniel.is.fischer at googlemail.com
Sun Jan 15 16:55:36 CET 2012


On Sunday 15 January 2012, 16:17:24, TP wrote:
> Hi,
> 
> I have a basic question concerning function composition. I have used
> http://www.haskell.org/tutorial/functions.html
> to write a composition function:
> 
> Prelude> let f°g = f g

This does not what you probably expect. That definition means (°) = ($) is 
just function application, or, in other words, (°) is the identity function 
restricted to function types.

If I'm correct in suspecting you want function composition,

Prelude> let f°g = f . g
Prelude> let (°) = (.)
Prelude> let (f ° g) x = f (g x)

are possible ways to obtain that.

> Prelude> let p = (*2)
> Prelude> let q = (+3)

These two lead to the surprise below.

> Prelude> p°q 4

This is parsed as

 p ° (q 4)

> 14
> Prelude> :t (°)
> (°) :: (t1 -> t) -> t1 -> t

(°) is the identity restricted to function types.

> 
> If I understand well, this means that the infix operator "°" takes a
> function of type t1, i.e. g in f°g,

it may be a function, but need not, it could also be a non-function value 
like [], True, ...

> and applies f on it, which takes a
> type t1 as input and returns f(g) which is of type t. The final result
> is of type t. So the first argument is represented above by "(t1->t)",
> and the second by "t1", the final result being of type t.
> 
> However, I am not able to get the type of p°q
> 
> Prelude> :t p°q
> 
> <interactive>:1:3:
>     Couldn't match expected type `Integer'
>                 with actual type `Integer -> Integer'
>     In the second argument of `(°)', namely `q'
>     In the expression: p ° q
> Prelude>
> 
> What's the problem here?

1. The monomorphism restriction. You have bound p and q

Prelude> let p = (*2)
Prelude> let q = (+3)

with simple pattern bindings (plain variable name, no function arguments in 
the binding) and without type signature. The inferred most general type for 
both is

Num a => a -> a

which is a constrained polymorphic type.

The monomorphism restriction (language report, section 4.5.5) says such 
bindings must have a monomorphic type.

By the defaulting rules (section 4.3.4), the type variable is defaulted to 
Integer to obtain a monomorphic type. Hence in your session, you have

p, q :: Integer -> Integer

Now, (°) :: (a -> b) -> a -> b, and matching p's type with the type of 
(°)'s first argument, a = b = Integer. But if we try to match q's type with 
the type of (°)'s second argument, that type has already been determined to 
be Integer here, so q's type (Integer -> Integer) doesn't match.

2. Even with the monomorhism eliminated, by one (or more) of

a) binding p and q with a function binding (let p x = x * 2)
b) giving a type signature for the binding
c) disabling the MR (Prelude> :set -XNoMonomorphismRestriction)

you still get something probably unexpected. now

p :: Num a => a -> a
q :: Num b => b -> b

unifying p's type with the type of (°)'s first argument,

(p °) :: Num a => a -> a

Now we must unify a with q's type, thus

(p ° q) :: (Num b, Num (b -> b)) => b -> b

> How can I obtain the type of p°q?

Eliminate the MR from the picture.

> 
> Thanks in advance,
> 
> TP




More information about the Haskell-Cafe mailing list