What is happening when I compose * with + in Haskell? - haskell

I'm trying to understand the result of
(*) . (+)
in Haskell. I know that the composition operator is just the standard composition of mathematical functions- so
(f . g) = f (g x)
But:
(*) . (+) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
I'm struggling to understand this type signature. I would have expected to be able to do things like:
((*) . (+)) 1 2 :: Num a => a -> a
= (* (+ 1 2))
What is the meaning of (*) . (+)'s type signature? I tried playing with it by something like (just matching up with its signature):
((*) . (+)) 1 (\x -> x + 1) 1
But that fails to compile. I'm trying to walk through the logical steps when composing these, but I'm not fully understanding how it's getting to this result (and what the result is).

I understand how you feel. I found function composition to be quite difficult to grasp at first too. What helped me grok the matter were type signatures. Consider:
(*) :: Num x => x -> x -> x
(+) :: Num y => y -> y -> y
(.) :: (b -> c) -> (a -> b) -> a -> c
Now when you write (*) . (+) it is actually the same as (.) (*) (+) (i.e. (*) is the first argument to (.) and (+) is the second argument to (.)):
(.) :: (b -> c) -> (a -> b) -> a -> c
|______| |______|
| |
(*) (+)
Hence the type signature of (*) (i.e. Num x => x -> x -> x) unifies with b -> c:
(*) :: Num x => x -> x -> x -- remember that `x -> x -> x`
| |____| -- is implicitly `x -> (x -> x)`
| |
b -> c
(.) (*) :: (a -> b) -> a -> c
| |
| |‾‾‾‾|
Num x => x x -> x
(.) (*) :: Num x => (a -> x) -> a -> x -> x
Hence the type signature of (+) (i.e. Num y => y -> y -> y) unifies with Num x => a -> x:
(+) :: Num y => y -> y -> y -- remember that `y -> y -> y`
| |____| -- is implicitly `y -> (y -> y)`
| |
Num x => a -> x
(.) (*) (+) :: Num x => a -> x -> x
| | |
| |‾‾‾‾| |‾‾‾‾|
Num y => y y -> y y -> y
(.) (*) (+) :: (Num (y -> y), Num y) => y -> (y -> y) -> y -> y
I hope that clarifies where the Num (y -> y) and Num y come from. You are left with a very weird function of the type (Num (y -> y), Num y) => y -> (y -> y) -> y -> y.
What makes it so weird is that it expects both y and y -> y to be instances of Num. It's understandable that y should be an instance of Num, but how y -> y? Making y -> y an instance of Num seems illogical. That can't be correct.
However, it makes sense when you look at what function composition actually does:
( f . g ) = \z -> f ( g z)
((*) . (+)) = \z -> (*) ((+) z)
So you have a function \z -> (*) ((+) z). Hence z must clearly be an instance of Num because (+) is applied to it. Thus the type of \z -> (*) ((+) z) is Num t => t -> ... where ... is the type of (*) ((+) z), which we will find out in a moment.
Therefore ((+) z) is of the type Num t => t -> t because it requires one more number. However, before it is applied to another number, (*) is applied to it.
Hence (*) expects ((+) z) to be an instance of Num, which is why t -> t is expected to be an instance of Num. Thus the ... is replaced by (t -> t) -> t -> t and the constraint Num (t -> t) is added, resulting in the type (Num (t -> t), Num t) => t -> (t -> t) -> t -> t.
The way you really want to combine (*) and (+) is using (.:):
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
f .: g = \x y -> f (g x y)
Hence (*) .: (+) is the same as \x y -> (*) ((+) x y). Now two arguments are given to (+) ensuring that ((+) x y) is indeed just Num t => t and not Num t => t -> t.
Hence ((*) .: (+)) 2 3 5 is (*) ((+) 2 3) 5 which is (*) 5 5 which is 25, which I believe is what you want.
Note that f .: g can also be written as (f .) . g, and (.:) can also be defined as (.:) = (.) . (.). You can read more about it here:
What does (f .) . g mean in Haskell?

(*) and (+) both have the type signature Num a => a -> a -> a
Now, if you compose them, you get something funky.
(*) . (+) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
That's because (*) and (+) are expecting two 'arguments'.
(+) with one argument gets you a function. The . operator expects that function (the a -> a that you see).
Here's the meaning of (*) . (+)
x f y
(*) . (+) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
(*) . (+) maps x f y to ((x +) * f) y where f is a function from a to a that is ALSO a number.
The reason (*) expects a function is to make the types match while it expects two arguments, but that function has to be a number because (*) only works on numbers.
Really, this function makes no sense at all.

Some extensions first:
{-# LANGUAGE FlexibleContexts, FlexibleInstances, TypeSynonymInstances #-}
As the other answers show, your function is
weird :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
weird x g = (x +) * g
But this function does have non-weird semantics.
There is a notion of difference lists. Accordingly, there is a notion of difference integers. I've seen them being used only in the dependently typed setting (e.g. here, but that's not the only case). The relevant part of the definition is
instance Enum DiffInt where
toEnum n = (n +)
fromEnum n = n 0
instance Num DiffInt where
n + m = n . m
n * m = foldr (+) id $ replicate (fromEnum n) m
This doesn't make much sense in Haskell, but can be useful with dependent types.
Now we can write
test :: DiffInt
test = toEnum 3 * toEnum 4
Or
test :: DiffInt
test = weird 3 (toEnum 4)
In both the cases fromEnum test == 12.
EDIT
It's possible to avoid the using of the TypeSynonymInstances extension:
{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
weird :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
weird x g = (x +) * g
instance (Enum a, Num a) => Enum (a -> a) where
toEnum n = (toEnum n +)
fromEnum n = fromEnum $ n (toEnum 0)
instance (Enum a, Num a) => Num (a -> a) where
n + m = n . m
n * m = foldr (+) id $ replicate (fromEnum n) m
type DiffInt = Int -> Int
As before we can write
test' :: DiffInt
test' = weird 3 (toEnum 4)
But now we can also write
-- difference ints over difference ints
type DiffDiffInt = DiffInt -> DiffInt
test'' :: DiffDiffInt
test'' = weird (toEnum 3) (toEnum (toEnum 4))
And
main = print $ fromEnum $ fromEnum test'
prints 12.
EDIT2 Better links added.

Let:
m = (*)
a = (+)
then
(m.a) x = (m (a x)) = m (a x)
Now m expects a Num a as a parameter, on the other hand (a x) , i.e. (x +) is a unary function (a -> a) by definition of (+). I guess what happened is that GHC tries to unite these two types so that, if you have a type that is both a number and a unary function, m can take a number and a unary function and return a unary function, since they are considered the same type.
As #Syd pointed, this unification wouldn't make sense for any normal number types such as integers and floating point numbers.

There are good answers here, but let me quickly point out a few steps where you went wrong.
First, the correct definition of function composition is
(f . g) x = f (g x)
you omitted the x on the LHS. Next, you should remember that in Haskell h x y is the same as (h x) y. So, contrary to what you expected,
((*) . (+)) 1 2 = (((*) . (+)) 1) 2 = ((*) ((+) 1)) 2 = ((+) 1) * 2,
and now you see why that fails. Also,
((*) . (+)) 1 (\x -> x + 1) 1
does not work, because the constraint Num (Int -> Int) is not satisfied.

Related

Understanding types in Haskell (lambda epxressions and higher order functions)

I'm currently doing a course in Haskell, and I have a lot of difficulty understanding the types of functions, particularly when there's function application or lambda expressions. Say for instance the following:
f = (\x -> \y -> \z -> [x (y z), y z])
or
g = \x -> \y -> \z -> x.y.z
I can sort of make some assumptions about the fact that x and y are functions, but I don't have a concrete method for figuring out the types of these functions.
Similarly for the following:
h = foldr (&&)
I try to guess and then check via :t in the interpreter, but I'm usually off by quite a bit.
Is there any particular method I can use to find the types of such functions?
You start by assigning type variables to the inputs and the result
f = (\x -> \y -> \z -> [x (y z), y z])
and conclude
f :: a -> b -> c -> d -- (A0)
-- or even (f is not needed)
\x -> \y -> \z -> [x (y z), y z] :: a -> b -> c -> d
that is
x :: a -- (1)
y :: b -- (2)
z :: c -- (3)
[x (y z), y z] :: d -- (4)
You can continue with (4) and conclude
that the type d is a list of d1s, i.e. d ~ [d1] (5)
f :: a -> b -> c -> [d1] -- (A1)
and that the values of the list are of type d1, i.e.
x (y z) :: d1 -- (6)
y z :: d1 -- (7)
From (6) you learn that
x :: e -> d1 -- (8)
y z :: e -- (9)
(1) and (8) unify, i.e. a ~ (e -> d1) and
f :: (e -> d1) -> b -> c -> [d1] -- (A2)
You play this game until you get bored and use GHCi to arrive at
f :: (d1 -> d1) -> (f -> d1) -> f -> [d1] -- (A3)
-- and renaming
f :: (a -> a) -> (b -> a) -> b -> [a] -- (A4)
If you want to learn more and read a paper you can start with Principal type-schemes for functional programs.
Prelude> :t h
h :: Foldable t => Bool -> t Bool -> Bool
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude> :t (&&)
(&&) :: Bool -> Bool -> Bool
Prelude>
By "plugging in" (&&) you have removed (a -> b -> b)
so you need to provide the rest to the function
b -> t a -> b
That is restricted by (&&) to be a bool as second param to it, and the second parameter is the t a which is also restricted to being a bool. since a and b needs to be the same type as in the (a->b->b) function.

Point free composition of multivariate functions

Say, we want to introduce the notion of sum of functions of different arguments (let's call it <+>), which behaves like the that: (f1 <+> f2)(x1, x2) == f1(x1) + f2(x2).
While this can be easily written out manually, it makes sense to use point-free style with the help of the notion of cartesian product of functions. The latter is defined below and seems alright and quite general to me:
x :: (x1 -> y1) -> (x2 -> y2) -> (x1 -> x2 -> (y1, y2))
x f1 f2 = \x1 x2 -> (f1(x1), f2(x2))
Then we can write:
(<+>):: Num a => (a -> a) -> (a -> a) -> (a -> a -> a)
(<+>) = (uncurry (+)) . x
And the code above seems fine to me too, but GHC thinks otherwise:
* Couldn't match type: (x20 -> y20) -> a -> x20 -> (a, y20)
with: ((a -> a) -> a -> a -> a, (a -> a) -> a -> a -> a)
Expected: (a -> a)
-> ((a -> a) -> a -> a -> a, (a -> a) -> a -> a -> a)
Actual: (a -> a) -> (x20 -> y20) -> a -> x20 -> (a, y20)
* Probable cause: `x' is applied to too few arguments
In the second argument of `(.)', namely `x'
In the expression: (uncurry (+)) . x
In an equation for `<+>': (<+>) = (uncurry (+)) . x
* Relevant bindings include
(<+>) :: (a -> a) -> (a -> a) -> a -> a -> a
It feels like the compiler cannot infer the second function's type, but why? And what am I supposed to do, is this even possible to do?
If you supply two arguments, you will see what has gone wrong.
(<+>) = uncurry (+) . x
(<+>) a = (uncurry (+) . x) a
= uncurry (+) (x a)
(<+>) a b = uncurry (+) (x a) b
Whoops! That b gets passed to uncurry as a third argument, rather than x as a second argument as you probably intended. The third and fourth arguments are also supposed to go to x rather than uncurry, as in:
(<+>) a b c d = uncurry (+) (x a b c d)
Here's the correct way to point-free-ify a four-argument composition.
\a b c d -> f (g a b c d)
= \a b c d -> (f . g a b c) d
= \a b c -> f . g a b c
= \a b c -> ((.) f . g a b) c
= \a b -> (.) f . g a b
= \a b -> ((.) ((.) f) . g a) b
= \a -> (.) ((.) f) . g a
= \a -> ((.) ((.) ((.) f)) . g) a
= (.) ((.) ((.) f)) . g
Most people then write this with section syntax as (((f .) .) .) . g. Applying this new fact to your case:
\a b c d -> uncurry (+) (x a b c d)
= (((uncurry (+) .) .) .) . x
The . operator is only for composing functions with a single argument, but the function x has four arguments, so you have to use . four times:
(<+>) = (((uncurry (+) .) .) .) . x
Do keep in mind that this is not considered good style in actual code.
Define
compose2 :: (b -> c -> t) -> (a -> b) -> (d -> c) -> a -> d -> t
compose2 p f g x y = p (f x) (g y)
Now, compose2 (+) is your <+>:
> :t compose2 (+)
compose2 (+) :: Num t => (a -> t) -> (d -> t) -> a -> d -> t
As you can see its type is a bit more general than you thought.
compose2 already exists.

Grouping parameters

Say I have functions which accept the same parameters and I want to test if their outputs are equivalent for the same input.
f :: a -> b -> c
g :: a -> b -> c
f a b == g a b
How can I package the parameters a and b in x so I can write the following instead.
f x == g x
What are the best ways to accomplish this without needing to wrap the functions themselves?
The only way to do exactly what you’re asking is to use uncurry:
let
x = (a, b)
in uncurry f x == uncurry g x
(Or uncurryN for N arguments.)
However, instead of packaging the arguments in a tuple, you could use the (->) x instance of Applicative (i.e., functions taking x as input) to implicitly “spread” the arguments to the parameters of both functions, so at least you only have to mention them once. This instance is commonly used in point-free code.
For example, using liftA2 specialised to this instance:
-- General type:
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
-- Specialised to ‘(->) x’ (using TypeApplications syntax):
liftA2 #((->) _) :: (a -> b -> c) -> (x -> a) -> (x -> b) -> (x -> c)
You get this pattern:
liftA2 h f g x
-- =
(h <$> f <*> g) x
-- =
h (f x) (g x)
To lift more arguments, you add another liftA2 or … <$> … <*> …:
liftA2 (liftA2 h) f g x y
-- =
(liftA2 h <$> f <*> g) x y
-- =
h (f x y) (g x y)
So in a case like yours:
f, g :: Int -> Char -> Bool
f i c = chr i == c
g i c = i == ord c
(liftA2 . liftA2) (==) f g :: Int -> Char -> Bool
-- =
liftA2 (liftA2 (==)) f g
-- =
(\ x y -> f x y == g x y)
The N in liftAN corresponds to the number of functions; the number of liftAN calls corresponds to the number of arguments.

Haskell: Flipping a curried dollar operator

Say I define this function:
f = ($ 5)
Then I can apply it:
> f (\x -> x ^ 2)
25
Its type is:
:t f
f :: (Integer -> b) -> b
Which makes sense, it gets a function as an argument, and returns this function applied on the Integer 5.
Now I define this function:
g = flip f
I would expect this to not make sense, because f is a function of a single argument.
But, checking its type:
:t g
g :: b -> (Integer -> b -> c) -> c
So now g is a function of 2 arguments!
Applying it on some values:
> g [2, 4, 6] (\x y -> x:y)
[5,2,4,6]
What is going on here? What does flip ($ 5) really mean?
Follow the types:
($ 5) :: (Int -> a) -> a
flip :: (x -> y -> z) -> y -> x -> z
But since -> is right associative, the type x -> y -> z is equivalent to x -> (y -> z), so
flip :: (x -> (y -> z)) -> y -> x -> z
($ 5) :: (Int -> a) -> a
So x ~ (Int -> a) and (y -> z) ~ a, so substituting back in:
($ 5) :: (Int -> (y -> z)) -> (y -> z)
And simplified
($ 5) :: (Int -> y -> z) -> y -> z
So
flip ($ 5) :: y -> (Int -> y -> z) -> z
Which is equivalent to the type you're seeing (although I used Int instead of Integer to save typing).
What this is saying is that the type of ($ 5) gets specialized when passed to flip such that it takes a function of 2 arguments. It is perfectly valid to have something like ($ 5) const, where const :: a -> b -> a and ($ 5) const :: b -> Int. All ($ 5) is doing is applying 5 as an argument to a function, not necessarily the argument for a function. This is an example of partial application, where not all of the arguments are supplied to a function. That's why you can do things like map (subtract 1) [1, 2, 3].
An example of how to use flip ($ 5) is:
> flip ($ 5) 2 (**)
25.0
> flip ($ 5) 1 (-)
4.0
> let f x y = (x, y)
> flip ($ 5) 1 f
(5, 1)
The confusion arises from the loose concept of "number of arguments" for polymorphic functions. For instance, it is tempting to say that
f :: (Integer -> b) -> b
has one argument (a function). Yet, a more precise statement would be that f is a function with at least one argument. This is because the type variable b can be substituted with any type, thanks to polymorphism, giving rise to e.g.
f :: (Integer -> String) -> String
f :: (Integer -> Double) -> Double
...
which are indeed functions with one argument, but also to, e.g.
f :: (Integer -> (String -> Double)) -> (String -> Double)
where b has been replaced with a functional type String -> Double. This substitution makes a second argument "appear" in an apparently magic way: f can take a first argument (a binary function Integer -> String -> Double), and then a second one (a String), before returning a Double.
Note that this phenomenon always appears when a polymorphic type ends with ... -> b for some type variable b.
Let me conclude with a trivia: how "many" arguments has the identity function id? Well, intuitively I would say one, but let me check ...
> id (+) 3 4
7
> id id id id id (+) 3 4
7
... and perhaps many is a better answer.
the function flip flips the order of the arguments, so all of these are equal:
f (\x y -> x:y) [2, 4, 6]
[5,2,4,6]
flip f [2, 4, 6] (\x y -> x:y)
[5,2,4,6]
g [2, 4, 6] (\x y -> x:y)
[5,2,4,6]

Recognizing haskell types

I'm having some difficulties in understanding the types in haskell. Let's consider the following functions and look at their types.
reduce f s [] = s
reduce f s (x:xs) = f x (reduce f s xs)
for m n f s = if m>n then s else for (m+1) n f ( f m s )
comp f g x y = f x (g x y)
iter 0 f s = s
iter n f s = iter (n-1) f (f s)
We'd have something like:
reduce :: (t1 -> t -> t) -> t -> [t1] -> t
for :: (Ord a, Num a) => a -> a -> (a -> t -> t) -> t -> t
comp :: (t -> t2 -> t3) -> (t -> t1 -> t2) -> t -> t1 -> t3
iter :: (Num t) => t -> (t1 -> t1) -> t1 -> t1
What I don't clearly understand is that in reduce function f takes two parameters, and in for function f again takes two parameters. All I can see is that it takes only one. Well if it would be something like that:
for m n f s = if m>n then s else for (m+1) n f m n
It would be more obvious and easy to recognize that f indeed takes two parameters.
I'm wondering if there exist some ways or method to deduce the types for functions in haskell. In addition to these examples I'd ask for some different examples, so that I can overcome that hardship.
EDIT: In my case function definitions are given, I am just trying to infer their types
Where you're making a thought mistake is in even considering f ( f m s ). That is not a subexpression of the for definition: recall that function application is parsed from the left. So
for (m+1) n f ( f m s )
≡ (for (m+1)) n f ( f m s )
≡ (for (m+1) n) f ( f m s )
≡ (for (m+1) n f) ( f m s )
≇ (for (m+1) n ) (f ( f m s ))
≇ for (m+1) (n f ( f m s ))
≇ for ((m+1) n f ( f m s ))
The last inequality is probably most obvious, because you'd be applying the function (m+1) to three arguments... that sure looks very unlikely.
If you need any "mental parenthesising" for understanding the function, it's normally best to put them around each function argument:
for (m+1) n f ( f m s )
≡ for (m+1)
(n)
(f)
(f m s)
and, if that helps you because it looks more like what you'd have in mainstream languages, you can also uncurry everything:
≅ for ( m+1, n, f, f(m,s) )
(though you'd better forget about that one quickly)
By the way: if you see a function applied to only one argument, it doesn't mean the function type has only one argument. In fact, the main strength of Haskell's curried syntax is that you can easily do partial application: e.g.
Prelude> :t take
take :: Int -> [a] -> [a]
Prelude> :t take 3
take 3 :: [a] -> [a]
Prelude> map (take 3) ["looooong", "even loonger", "terribly long"]
["loo","eve","ter"]
You see I've only applied take to one argument, the other one is automatically taken from the list by map.
Another example, with operator sections,
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t (+ 1)
(+ 1) :: Num a => a -> a
Prelude> map (+ 1) [4,5,6]
[5,6,7]
The type of f in the following definition is quite easy to infer
for m n f s = if m>n then s else for (m+1) n f ( f m s )
This could be rewritten (for clearity) as
for m n f s
| m>n = s
| otherwise = for (m+1) n f ( f m s )
for (m+1) n f (f m s) is a call of for,
which means f m s needs has the same type as s,
this requires f to have type t1 -> t -> t
(t1 for m, and t for s)

Resources