RippeR
RippeR

Reputation: 1472

Haskell function composition, type of (.)(.) and how it's presented

So i know that:

(.) = (f.g) x = f (g x)

And it's type is (B->C)->(A->B)->A->C But what about:

(.)(.) = _? = _?

How this is represented? I thought of:

(.)(.) = (f.g)(f.g)x = f(g(f(g x))) // this
(.)(.) = (f.g.h)x = f(g(h x)) // or this

But as far as i tried to get type of it, it's not correct to what GHCi tells me. So what are both "_?"

Also - what does function/operator $ do?

Upvotes: 3

Views: 2513

Answers (2)

Will Ness
Will Ness

Reputation: 71065

As dave4420 mentions,

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

So what is the type of (.) (.)? dave4420 skips that part, so here it is: (.) accepts a value of type b -> c as its first argument, so

(.) :: (   b     ->       c             ) -> (a -> b) -> a -> c
(.) ::  (d -> e) -> ((f -> d) -> f -> e)

so we have b ~ d->e and c ~ (f -> d) -> f -> e, and the resulting type of (.)(.) is (a -> b) -> a -> c. Substituting, we get

(a -> d -> e) -> a -> (f -> d) -> f -> e

Renaming, we get (a -> b -> c) -> a -> (d -> b) -> d -> c. This is a function f that expects a binary function g, a value x, a unary function h and another value y:

f g x h y = g x (h y)

That's the only way this type can be realized: g x :: b -> c, h y :: b and so g x (h y) :: c, as needed.

Of course in Haskell, a "unary" function is such that expects one or more arguments; similarly a "binary" function is such that expects two or more arguments. But not less than two (so using e.g. succ is out of the question).


We can also tackle this by writing equations, combinators-style1. Equational reasoning is easy:

(.) (.) x y z w q = 
((.) . x) y z w q =
(.) (x y) z w q =
(x y . z) w q =
x y (z w) q 

We just throw as much variables as needed into the mix and then apply the definition back and forth. q here was an extra, so we can throw it away and get the final definition,

_BB x y z w = x y (z w)

(coincidentally, (.) is known as B-combinator).


1 a b c = (\x -> ... body ...) is equivalent to a b c x = ... body ..., and vice versa, provided that x does not appear among {a,b,c}.

Upvotes: 7

dave4420
dave4420

Reputation: 47052

First off, you're being sloppy with your notation.

(.) = (f.g) x = f (g x)  -- this isn't true

What is true:

(.) f g x = (f.g) x = f (g x)
(.) = \f g x -> f (g x)

And its type is given by

(.) :: (b -> c) -> (a -> b) -> a -> c
       -- n.b. lower case, because they're type *variables*

Meanwhile

(.)(.) :: (a -> b -> d) -> a -> (c -> b) -> c -> d
          -- I renamed the variables ghci gave me

Now let's work out

(.)(.) = (\f' g' x' -> f' (g' x')) (\f g x -> f (g x))
       = \g' x' -> (\f g x -> f (g x)) (g' x')
       = \g' x' -> \g x -> (g' x') (g x)
       = \f y -> \g x -> (f y) (g x)
       = \f y g x -> f y (g x)
       = \f y g x -> (f y . g) x
       = \f y g -> f y . g

And ($)?

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

($) is just function application. But whereas function application via juxtaposition is high precedence, function application via ($) is low precedence.

square $ 1 + 2 * 3 = square (1 + 2 * 3)
square 1 + 2 * 3 = (square 1) + 2 * 3  -- these lines are different

Upvotes: 14

Related Questions