I am studying Haskell. Currently, I am studying function composition. I understand (at least on a basic level) how function (.) can be used, but there are two things to it that I understand not.
So the function looks as follows:
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
First, the type declaration. (b -> c) -> (a -> b) essentially means that function f takes an argument from resulting value (b) of function g (which takes value a) and returns value of type c. I don't understand the following part -> a -> c, why should there be -> a there? Why is (b -> c) -> (a -> b) -> c wrong? From my point of view (which is obviously wrong), function g is already taking a as an argument.
Second, the body of the function f . g = \x -> f (g x). What does \x -> do here? Lambda is pretty straightforward. For example filter (\(a,b) -> a + b > 4) [(1,2),(3,4)], but a simple \x -> makes me stuck. I would probably write the body like this f . (g x) = f (g x) (which is obviously wrong again).
(b -> c) -> (a -> b) -> c would be a function that takes two functions f :: b -> c and g :: a -> b, and somehow call g without an initial argument of type a.
For the second question, consider how you would define (.) using prefix notation instead. (It might be easier to see if we use a "regular" name for the function; I'll include that as a comment after each snippet of code):
(.) f g x = f (g x) -- compose f g x = f (g x)
x is the "third argument" for (.), or more precisely the argument for the function returned by (.) f g. This is equivalent to defining (.) f g as a function directly, by putting a function on the right-hand side instead of the ultimate return value of that function:
(.) f g x = f (g x) -- Implicit function def: compose f g x = f (g x)
(.) f g = \x -> f (g x) -- Explicit function def: compose f g = \x -> f (g x)
You can also use parentheses to define the function implicitly:
(f . g) x = f (g x)
I'm a newbe in functional programming, and I'm trying to solve the following exercise;
Given the type
type Cont r a = (a -> r) -> r
Implement the following higher-order function
mapReader :: (a -> b) -> (Cont r a) -> Cont r b
The first step would be to simplify the types, which gives:
mapReader :: (a -> b) -> ((a -> r) -> r) -> (b -> r) -> r
Next, define the parameters that need to be provided in this function. These parameters are three functions so we get
mapReader :: (a -> b) -> ((a -> r) -> r) -> (b -> r) -> r
mapReader f g h = _1
From here, we can define the following types:
f :: a -> b
g :: (a -> r) -> r
h :: b -> r
_1 :: r
But now I'm stuck. There are two functions that result in r, and one of them contains another function (a -> r). How can I start defining r? Any hints are much appreciated!
We have
f :: a -> b
g :: (a -> r) -> r
h :: b -> r
and we need
_1 :: r
There are two ways we can make r: g and h.
Let's try using h. h takes an argument of type b. The only way to get one of those is using f. f takes an argument of type a, and ... we don't have any way to get one of those.
So now let's try using g instead:
mapReader f g h = g _2
We're told
_2 :: a -> r
Since we're constructing a function, we can apply lambda abstraction as usual:
mapReader f g h = g (\a -> _3)
a :: a
_3 :: r
But wait ... now we have an a, so we can go back to our first attempt:
mapReader f g h = g (\a -> h (f a))
Or, more compactly,
mapReader f g h = g (h . f)
What if instead of going back to the first attempt we did it the second way again?
mapReader' f g h =
g (\a1 -> g (\a2 -> _4))
_4 :: r
You could go this way forever, but you could also stop here in two different ways:
mapReader2 f g h =
g (\_ -> g (h . f))
mapReader3 f g h =
g (\a1 -> g (\_ -> h (f a1)))
Oy! These are three different functions that all have the same type, and as shown this approach can be used to generate an infinite family of functions! How can you decide which one you want? You have to consider the intention. g's argument is the continuation, so you want to compose a function with what you're passing g, not call g multiple times. So mapReader is the "correct" answer.
More precisely, mapReader is supposed to map morphisms for the continuation functor. That requires in particular that
mapReader id = id
That is,
mapReader id g h = g (h . id)
= g h
That's unconditionally true for the correct definition, but not for any of the others.
Start by looking at what you can do with the three arguments.
You can compose f and h: h . f :: a -> r.
You can apply g to h . f: g (h . f) :: r.
So you could simply say that mapReader f g h = g (h . f). There's not enough information here to specify what r is; it depends entirely on what
arguments g and h are given to mapReader.
So you have
f :: a -> b
h :: b -> r
g :: (a -> r) -> r
There's also the forward functional composition operator,
(>>>) :: (a -> b) -> (b -> r) -> (a -> r)
and the reversed application operator,
(&) :: t -> (t -> r) -> r
so that
f >>> h :: ......... -- what?
and
(f >>> h) & g :: ......... -- what else?
Can you come up with the definitions of (>>>) and (&), just from their types?
Let me get you started on the first one.
(>>>) :: (a -> b) -> (b -> r) -> (a -> r)
means that
(>>>) (f :: a -> b) :: (b -> r) -> (a -> r)
(>>>) (f :: a -> b) (g :: b -> r) :: (a -> r)
(>>>) (f :: a -> b) (g :: b -> r) (x :: a) :: r
So again we write them down
f :: a -> b
g :: b -> r
x :: a
f x :: b
g (f x) :: ....
And that's that.
The most important rule that we used here, is
x :: a
f :: a -> r
f x :: r
. :: (a -> b) -> (c -> a) -> c -> b
f . g = \ x -> f (g x)
Why is this definition illegal? Aesthetic choice, or formal necessity?
It's for consistency. Infix operators by themselves aren't expressions whose type or value you could define. The following is also not legal:
. = \f g x -> f (g x)
...though that is basically what your definition is desugared to. But for directly defining the value of an infix this way, we need to first disable the special syntactic status, and that's done by wrapping it in parentheses:
(.) :: (a -> b) -> (c -> a) -> c -> b
(.) = \f g x -> f (g x)
This is quite the same as defining
compose :: (a -> b) -> (c -> a) -> c -> b
compose = \f g x -> f (g x)
...which can then also be used as an infix, like
Prelude> map (toEnum `compose` round) $ [110 + sin x * 12 | x<-[0..30]] :: String
"nxypebkvzsgbhszvkbepyxndclwyqfb"
But you obviously wouldn't write the definition in infix form, like
`compose` :: (a -> b) -> (c -> a) -> c -> b
`compose` = \f g x -> f (g x)
...though you could do
f`compose`g = \x -> f (g x)
It is not clear to me why the function defined as
f g x = g . g x
has the type
f :: (b -> a -> b) -> b -> a -> a -> b
I would have thought it would be of type
f :: (t -> t) -> t -> t
Can anyone explain to me how the expression is broken down? Thanks!
Note that function application has the highest priority; operators come later.
So, the term g . g x first applies g to x, and then composes the result and g itself. If x has type b, g must have type b -> c. Since we compose g with g x (the latter of type c), c must be a function type returning b, so c = a -> b. Now, the type of g is b -> a -> b and the type of g . g x is a -> (a -> b); the type of f happens to be (b -> a -> b) -> b -> a -> a -> b.
If you wanted something like (a -> a) -> a -> a instead, you could try one of this
f g x = g (g x)
f g x = (g . g) x
f g x = g . g $ x
f g = g . g
The idea is about understanding the (.) operator, it has a type of
(.) :: (b -> c) -> (a -> b) -> a -> c
It takes two functions each with one parameter and compose them, after applying g x the compiler assumed g is actually g :: a -> b -> c in order to satisfy the signature of (.) :: (b -> c) -> (a -> b) -> a -> c which takes two functions with one argument. Otherwise the code won't compile.
And finally if you want the signature f :: (t -> t) -> t -> t you need something like this:
λ> let applyTwice g = g.g
λ> :t applyTwice
applyTwice :: (a -> a) -> a -> a
λ> applyTwice (*2) 3
12
(.) takes two functions that take one value and return a value:
(.) :: (b -> c) -> (a -> b) -> a -> c
Since (.) takes two arguments, I feel like (.).(.) should be invalid, but it's perfectly fine:
(.).(.) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
What is going on here? I realize this question is badly worded...all functions really just take one argument thanks to currying. Maybe a better way to say it is that the types don't match up.
Let's first play typechecker for the mechanical proof. I'll describe an intuitive way of thinking about it afterward.
I want to apply (.) to (.) and then I'll apply (.) to the result. The first application helps us to define some equivalences of variables.
((.) :: (b -> c) -> (a -> b) -> a -> c)
((.) :: (b' -> c') -> (a' -> b') -> a' -> c')
((.) :: (b'' -> c'') -> (a'' -> b'') -> a'' -> c'')
let b = (b' -> c')
c = (a' -> b') -> a' -> c'
((.) (.) :: (a -> b) -> a -> c)
((.) :: (b'' -> c'') -> (a'' -> b'') -> a'' -> c'')
Then we begin the second, but get stuck quickly...
let a = (b'' -> c'')
This is key: we want to let b = (a'' -> b'') -> a'' -> c'', but we already defined b, so instead we must try to unify --- to match up our two definitions as best we can. Fortunately, they do match
UNIFY b = (b' -> c') =:= (a'' -> b'') -> a'' -> c''
which implies
b' = a'' -> b''
c' = a'' -> c''
and with those definitions/unifications we can continue the application
((.) (.) (.) :: (b'' -> c'') -> (a' -> b') -> (a' -> c'))
then expand
((.) (.) (.) :: (b'' -> c'') -> (a' -> a'' -> b'') -> (a' -> a'' -> c''))
and clean it up
substitute b'' -> b
c'' -> c
a' -> a
a'' -> a1
(.).(.) :: (b -> c) -> (a -> a1 -> b) -> (a -> a1 -> c)
which, to be honest, is a bit of a counterintuitive result.
Here's the intuition. First take a look at fmap
fmap :: (a -> b) -> (f a -> f b)
it "lifts" a function up into a Functor. We can apply it repeatedly
fmap.fmap.fmap :: (Functor f, Functor g, Functor h)
=> (a -> b) -> (f (g (h a)) -> f (g (h b)))
allowing us to lift a function into deeper and deeper layers of Functors.
It turns out that the data type (r ->) is a Functor.
instance Functor ((->) r) where
fmap = (.)
which should look pretty familiar. This means that fmap.fmap translates to (.).(.). Thus, (.).(.) is just letting us transform the parametric type of deeper and deeper layers of the (r ->) Functor. The (r ->) Functor is actually the Reader Monad, so layered Readers is like having multiple independent kinds of global, immutable state.
Or like having multiple input arguments which aren't being affected by the fmaping. Sort of like composing a new continuation function on "just the result" of a (>1) arity function.
It's finally worth noting that if you think this stuff is interesting, it forms the core intuition behind deriving the Lenses in Control.Lens.
Let’s ignore types for a moment and just use lambda calculus.
Desugar infix notation:
(.) (.) (.)
Eta-expand:
(\ a b -> (.) a b) (\ c d -> (.) c d) (\ e f -> (.) e f)
Inline the definition of (.):
(\ a b x -> a (b x)) (\ c d y -> c (d y)) (\ e f z -> e (f z))
Substitute a:
(\ b x -> (\ c d y -> c (d y)) (b x)) (\ e f z -> e (f z))
Substitute b:
(\ x -> (\ c d y -> c (d y)) ((\ e f z -> e (f z)) x))
Substitute e:
(\ x -> (\ c d y -> c (d y)) (\ f z -> x (f z)))
Substitute c:
(\ x -> (\ d y -> (\ f z -> x (f z)) (d y)))
Substitute f:
(\ x -> (\ d y -> (\ z -> x (d y z))))
Resugar lambda notation:
\ x d y z -> x (d y z)
And if you ask GHCi, you’ll find that this has the expected type. Why? Because the function arrow is right-associative to support currying: the type (b -> c) -> (a -> b) -> a -> c really means (b -> c) -> ((a -> b) -> (a -> c)). At the same time, the type variable b can stand for any type, including a function type. See the connection?
Here is a simpler example of the same phenomenon:
id :: a -> a
id x = x
The type of id says that id should take one argument. And indeed, we can call it with one argument:
> id "hello"
"hello"
But it turns out what we can also call it with two arguments:
> id not True
False
Or even:
> id id "hello"
"hello"
What is going on? The key to understanding id not True is to first look at id not. Clearly, that's allowed, because it applies id to one argument. The type of not is Bool -> Bool, so we know that the a from id's type should be Bool -> Bool, so we know that this occurrence of id has type:
id :: (Bool -> Bool) -> (Bool -> Bool)
Or, with less parentheses:
id :: (Bool -> Bool) -> Bool -> Bool
So this occurrence of id actually takes two arguments.
The same reasoning also works for id id "hello" and (.) . (.).
This is one of those neat cases where I think it's simpler to grasp the more general case first, and then think about the specific case. So let's think about functors. We know that functors provide a way to map functions over a structure --
class Functor f where
fmap :: (a -> b) -> f a -> f b
But what if we have two layers of the functor? For example, a list of lists? In that case we can use two layers of fmap
>>> let xs = [[1,2,3], [4,5,6]]
>>> fmap (fmap (+10)) xs
[[11,12,13],[14,15,16]]
But the pattern f (g x) is exactly the same as (f . g) x so we could write
>>> (fmap . fmap) (+10) xs
[[11,12,13],[14,15,16]]
What is the type of fmap . fmap?
>>> :t fmap.fmap
:: (Functor g, Functor f) => (a -> b) -> f (g a) -> f (g b)
We see that it maps over two layers of functor, as we wanted. But now remember that (->) r is a functor (the type of functions from r, which you might prefer to read as (r ->)) and its functor instance is
instance Functor ((->) r) where
fmap f g = f . g
For a function, fmap is just function composition! When we compose two fmaps we map over two levels of the function functor. We initially have something of type (->) s ((->) r a), which is equivalent to s -> r -> a, and we end up with something of type s -> r -> b, so the type of (.).(.) must be
(.).(.) :: (a -> b) -> (s -> r -> a) -> (s -> r -> b)
which takes its first function, and uses it to transform the output of the second (two-argument) function. So for example, the function ((.).(.)) show (+) is a function of two arguments, that first adds its arguments together and then transforms the result to a String using show:
>>> ((.).(.)) show (+) 11 22
"33"
There is then a natural generalization to thinking about longer chains of fmap, for example
fmap.fmap.fmap ::
(Functor f, Functor g, Functor h) => (a -> b) -> f (g (h a)) -> f (g (h b))
which maps over three layers of functor, which is equivalent to composing with a function of three arguments:
(.).(.).(.) :: (a -> b) -> (r -> s -> t -> a) -> (r -> s -> t -> b)
for example
>>> import Data.Map
>>> ((.).(.).(.)) show insert 1 True empty
"fromList [(1,True)]"
which inserts the value True into an empty map with key 1, and then converts the output to a string with show.
These functions can be generally useful, so you sometimes see them defined as
(.:) :: (a -> b) -> (r -> s -> a) -> (r -> s -> b)
(.:) = (.).(.)
so that you can write
>>> let f = show .: (+)
>>> f 10 20
"30"
Of course, a simpler, pointful definition of (.:) can be given
(.:) :: (a -> b) -> (r -> s -> a) -> (r -> s -> b)
(f .: g) x y = f (g x y)
which may help to demystify (.).(.) somewhat.
You're right, (.) only takes two arguments. You just seem to be confused with the syntax of haskell. In the expression (.).(.), it's in fact the dot in the middle that takes the other two dots as argument, just like in the expression 100 + 200, which can be written as (+) 100 200.
(.).(.) === (number the dots)
(1.)2.(3.) === (rewrite using just syntax rules)
(2.)(1.)(3.) === (unnumber and put spaces)
(.) (.) (.) ===
And it should be even more clear from (.) (.) (.) that the first (.) is taking the second (.) and third (.) as it's arguments.
Yes this is due to currying. (.) as all functions in Haskell only takes one argument. What you are composing is the first partial call to each respective composed (.) which takes its first argument (the first function of the composition).
(Read my answer on function composition, $ operator and point-free style first.)
Imagine you have a simple function: it adds up 2 numbers and then negates the result. We'll call it foo:
foo a b = negate (a + b)
Now let's make it point-free step by step and see what we end up with:
foo a b = negate $ a + b
foo a b = negate $ (+) a b
foo a b = negate $ (+) a $ b
foo a b = negate . (+) a $ b
foo a = negate . (+) a -- f x = g x is equivalent to f = g
foo a = (.) negate ((+) a) -- any infix operator is just a function
foo a = (negate.) ((+) a) -- (2+) is the same as ((+) 2)
foo a = (negate.) $ (+) a
foo a = (negate.) . (+) $ a
foo = (negate.) . (+)
foo = ((.) negate) . (+)
foo = (.) ((.) negate) (+) -- move dot in the middle in prefix position
foo = ((.) ((.) negate)) (+) -- add extra parentheses
Now let's analyze expression (.) ((.) negate) more closely. It's a partial application of (.) function, whose first argument is ((.) negate). Can we transform it even further? Yes we can:
(.) ((.) negate)
(.) . (.) $ negate -- because f (f x) is the same as (f . f) x
(.)(.)(.) $ negate
((.)(.)(.)) negate
(.).(.) is equivalent to (.)(.)(.), because in the 1st expression, the dot in the middle can be moved in prefix position and surrounded with parentheses, which gives rise to the 2nd expression.
Now we can rewrite our foo function:
foo = ((.).(.)) negate (+)
foo = ((.)(.)(.)) negate (+) -- same as previous one
foo = negate .: (+)
where (.:) = (.).(.)
Now you know that (.).(.) is equivalent to (\f g x y -> f (g x y)):
(\f g x y -> f (g x y)) negate (+) 2 3 -- returns -5
((.).(.)) negate (+) 2 3 -- returns -5