I am a beginner in Haskell and I come across the function (.)(.)
, I use :t
to get its type in GHCi:
:t (.)(.)
(.)(.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
How to understand the type (.)(.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
here? I am very confused.
The most basic way of defining a function in Haskell is to ``declare'' what it does. For example, we can write: double :: Int -> Int double n = 2*n. Here, the first line specifies the type of the function and the second line tells us how the output of double depends on its input.
Elementary HaskellA function that takes another function (or several functions) as an argument is called a higher-order function. They can be found pretty much anywhere in a Haskell program, and indeed we have already met some of them, such as map and the various folds.
In Haskell read function is used to deal with strings, if you want to parse any string to any particular type than we can use read function from the Haskell programming. In Haskell read function is the in built function, that means we do not require to include or install any dependency for it, we can use it directly.
The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.
This is a partial application of the composition operator to the composition operator itself. In general, we know that if we apply (.)
to some function f :: x -> y
, then
>>> :t (.) f
(.) f :: (a -> x) -> a -> y
because of how the types line up:
(b -> c) -> (a -> b) -> a -> c
x -> y
--------------------------------
(a -> x) -> a -> y
We drop the first argument, and replace remaining occurrences of b
and c
with the corresponding types of the given argument.
Here, f
is just (.)
again, meaning we identify x ~ (b -> c)
and y ~ (a -> b) -> a -> c
. Lining up the types again
(a -> x ) -> a -> y
b -> c (a -> b) -> a -> c
Since a
occurs on the top and the bottom, we need to pick a new variable name for a
on the bottom; GHC chose a1
:
(a -> x ) -> a -> y
b -> c (a1 -> b) -> a1 -> c
Putting the two together yields the type you see in GHCi.
(a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
Anatomy jokes aside, what is (.)(.)
?
Let's say you have a function f :: a -> b
, but you want a function g :: a -> c
, that is, you want f
but with a different return type. The only thing you can do is find a helper function h :: b -> c
that will convert the return value for you. Your function g
is then simply the composition of h
and f
:
g = h . f
You might, however, have a more general function h' :: t -> b -> c
, which can
turn values of type b
into values of type c
in multiple ways, depending on the value of some argument x :: t
. Then you could get lots of different g
s depending on that argument.
g = (h' x) . f
Now, given h'
, x
, and f
, we can return our g
, so let's write a function that does that: a function that "promotes" the return value of f
from a value of type b
to a value of type c
, given a function h'
and some value x
:
promote h' x f = (h' x) . f
You can mechanically convert any function to point-free form; I'm not familiar with the details, but using PointFree.io produces
promote = ((.) .)
which is just the partial application (.) (.)
written as a section, that is:
((.) (.)) h' x f == (h' x) . f
So, our "boobs" operator is just a generalized pre-composition operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With