I am in the process of teaching myself Haskell and I was wondering about the following type signatures:
Prelude> :t ($)
($) :: (a -> b) -> a -> b
Prelude>
How should I interpret (no pun intended) that?
A semi-similar result is also proving to be puzzling:
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude>
I'll start with map. The map function applies an operation to every element in a list. If I had
add3 :: Int -> Int
add3 x = x + 3
Then I could apply this to a whole list of Ints using map:
> map add3 [1, 2, 3, 4]
[4, 5, 6, 7]
So if you look at the type signature
map :: (a -> b) -> [a] -> [b]
You'll see that the first argument is (a -> b), which is just a function that takes an a and returns a b. The second argument is [a], which is a list of values of type a, and the return type [b], a list of values of type b. So in plain english, the map function applies a function to each element in a list of values, then returns the those values as a list.
This is what makes map a higher order function, it takes a function as an argument and does stuff with it. Another way to look at map is to add some parentheses to the type signature to make it
map :: (a -> b) -> ([a] -> [b])
So you can also think of it as a function that transforms a function from a to b into a function from [a] to [b].
The function ($) has the type
($) :: (a -> b) -> a -> b
And is used like
> add3 $ 1 + 1
5
All it does is take what's to the right, in this case 1 + 1, and passes it to the function on the left, here add3. Why is this important? It has a handy fixity, or operator precedence, that makes it equivalent to
> add3 (1 + 1)
So whatever to the right gets essentially wrapped in parentheses before being passed to the left. This just makes it useful for chaining several functions together:
> add3 $ add3 $ add3 $ add3 $ 1 + 1
is nicer than
> add3 (add3 (add3 (add3 (1 + 1))))
because you don't have to close parentheses.
Well, as said already, $ can be easily understood if you just forget about currying and see it like, say, in C++
template<typename A, typename B>
B dollar(std::function<B(A)> f, A x) {
return f(x);
}
But actually, there is more to this than just applying a function to a value! The apparent similarity between the signatures of $ and map has in fact a pretty deep category-theory meaning: both are examples of the morphism-action of a functor!
In the category Hask that we work with all the time, objects are types. (That is a bit confusionsome, but don't worry). The morphisms are functions.
The most well-known (endo-)functors are those which have an instance of the eponymous type class. But actually, mathematically, a functor is only something that maps both objects to objects and morphisms to morphisms1. map (pun intended, I suppose!) is an example: it takes an object (i.e. type) A and maps it to a type [A]. And, for any two types A and B, it takes a morphism (i.e. function) A -> B, and maps it to the corresponding list-function of type [A] -> [B].
This is just a special case of the functor class signature operation:
fmap :: Functor f => (a->b) -> (f a->f b)
Mathematics doesn't require this fmap to have a name though. And so there can be also the identity functor, which simply assigns any type to itself. And, every morphism to itself:
($) :: (a->b) -> (a->b)
"Identity" exists obviously more generally, you can also map values of any type to themselves.
id :: a -> a
id x = x
And sure enough, a possible implementation is then
($) = id
1Mind, not anything that maps objects and morphisms is a functor... it does need to satisfy the functor laws.
($) is just function application. It gets a function of type a->b, an argument of type a, applies the function and returns a value of type b.
map is a wonderful example for how reading a function type signature helps understanding it. map's first argument is a function that takes a and returns b, and its second argument is a list of type [a].
So map applies a function of type a->b to a list of a values. And the result type is indeed of type [b] - a list of b values!
(a->b)->[a]->[b] can be interpreted as "Accepts a function and a list and returns another list", and also as "Accepts a function of type a->b and returns another function of type [a]->[b]".
When you look at it this way, map "upgrade" f (the term "lift" is often used in this context) to work on lists: if double is a function that doubles an integer, then map double is a function that double every integer in a list.
Related
I understand that the $ operator is for avoiding parentheses. Anything appearing after it will take precedence over anything that comes before.
I am trying to understand what it means in this context:
map ($ 3) [(+),(-),(/),(*)]
With the following code:
instance Show (a -> b) where
show a = function
main = putStrLn $ show $ map ($ 3) [(+),(-),(/),(*)]
The output is
["function", "function", "function", "function"]
This doesn't help me understand the meaning of the $ here.
How can I display more helpful output?
($) :: (a -> b) -> a -> b is a function that takes a function as first parameter, and a value as second and returns the value applied to that function.
For example:
Prelude> (1+) $ 2
3
The expression ($ 3) is an example of infix operator sectioning [Haskell-wiki]. ($ 3) is short for \f -> f $ 3, or simpler \f -> f 3. It thus is a function that takes a function and applies 3 to that function.
For your expression:
map ($ 3) [(+),(-),(/),(*)]
the output is thus equivalent to:
[(3+), (3-), (3/), (3*)] :: Fractional a => [a -> a]
Since (+), (-), (*) :: Num a => a -> a -> a work with types that are members of the Num typeclass, and (/) :: Fractional a => a -> a -> a works with types that are members of the Fractional type class, and all Fractional types are num types as well, 3 is here a Fractional type, and the list thus contains functions that are all of the type a -> a with a a member of Fractional.
How can I display more helpful output?
The compiler does not keep track of the expressions, as specified in the Haskell wiki page on Show instance for functions [Haskell-wiki].
The Haskell compiler doesn't maintain the expressions as they are, but translates them to machine code or some other low-level representation. The function \x -> x - x + x :: Int -> Int might have been optimized to \x -> x :: Int -> Int. If it's used anywhere, it might have been inlined and optimized to nothing. The variable name x is not stored anywhere. (...)
So we can not "look inside" the function and derive an expression that is human-readable.
I've recently started trying to learn Haskell by reading LearnYouAHaskell and random articles from the internet.
I'm having hard time understanding more sophisticated function types.
Some examples that I understand.
> :t map
map :: (a -> b) -> [a] -> [b]
It takes in a function (which takes a and gives out b, i.e a and b can be of different types) and a list of a's and return a list of b's.
> :t fst
fst :: (a, b) -> a
Takes in a tuple of 2 elements (allows different types) and returns the first one.
> :t any
At a higher level, I understand any. It takes in a function and a list and returns true if any of the list entries return true for that particular function. I've used it in Python and JavaScript as well.
Questions
I don't understand how does any :: Foldable t => (a -> Bool) -> t a -> Bool
translate to the above.
(a -> Bool) is the predicate. Takes in an argument and returns true or false.
t a -> Bool Bool is the end result of any. According to my understanding t and a represent the predicate and the list. Why aren't they separated by a ->
How to go about understanding type signatures in general and how to dig deeper so that I can approach them myself?
any :: Foldable t => (a -> Bool) -> t a -> Bool
Here Foldable t means, that t is an instance of type class Foldable.
Foldable is a type class and if type t is an instance of the type class Foldable we know from the t a part of the signature or from the definition of the type class Foldable, that t is actually a type constructor.
So t a is a type and therefore t a -> Bool is a function, that maps a value of type t a to Bool. This function will be closure, which will
apply the predicate to each "element" of the value of type t a, until it finds one, that yields True under the predicate or it doesn't find such an element returning either True or False in the respective cases. (The actual implementation might be very different.)
For example [] is an instance of the type class Foldable and therefore t a could be a list of something. In this case, we can also write [a] instead of [] a.
But there are other type constructors, which can be instances of Foldable, for example some kinds of trees.
It might be helpful to note that until recently, the signature was actually
any :: (a -> Bool) -> [a] -> Bool
This was generalised during the Foldable Traversable in Prelude proposal: now the container of values need not be a list, but can as well be e.g. an array:
Prelude> import qualified Data.Vector as Arr
Prelude Arr> :set -XOverloadedLists
Prelude Arr> let a = [1,2,3] :: Arr.Vector Int
Prelude Arr> any (>2) a
True
Type signature is a mark up designation of the function indicating the types to be processed and how the function can be partially applied.
Foldable t => (a -> Bool) -> t a -> Bool
By Foldable t it first says any function can work with any data type which is an instance of Foldable type class.
The first parameter, (a -> Bool) is obviously a function which takes a single element (a) from our foldable data type and returns a Bool type value. It's the the callback of .some(callback) in JavaScript. When you apply this parameter to any you will be returned with a function of type;
t a -> Bool
Now we are left with a single function which takes only one parameter and returns a Bool type (True or False) value. Again t a is a data type which is a member of the Foldable type class. It can be a [] but a Tree too provided that the data type has foldMap function defined under an instance to Foldable. It's the myArr part in JavaScript's myArr.some(callback) except that it doesn't have to be an array.
t a isn't separated by a -> because the t a is the instance of foldable, ex: List a, or Tree a. Let's go back to map for a second. The version you gave is specialized to lists; a more general version (which, as an accident of history, is called fmap in most versions of Haskell) has type fmap :: Functor f => (a->b) -> f a -> f b. Where is your input list in this signature? It's the f a. Now, returning to any the t a is the second argument, the instance of Foldable you're folding over, the list or tree or whatever.
You'll read that all functions in Haskell really have only 1 argument, and we're seeing that here. any takes it's first argument (the predicate) and returns a function that takes a foldable (the list, tree, etc) and returns a Bool.
t a does not represent the predicate and the list. As you've already correctly pointed out before, (a -> Bool) is the predicate. t a just represents the list, except it doesn't have to be a list (that's why it's t a instead of [a]). t can be any Foldable, so it could be [], but it could also be some other collection type or Maybe.
I want to use applicative function and tried as follow:
*ReaderExercise Control.Applicative> (+4) <*> (+3)
then got following error message:
<interactive>:51:11: error:
* Occurs check: cannot construct the infinite type: a ~ a -> b
Expected type: (a -> b) -> a
Actual type: a -> a
* In the second argument of `(<*>)', namely `(+ 3)'
In the expression: (+ 4) <*> (+ 3)
In an equation for `it': it = (+ 4) <*> (+ 3)
* Relevant bindings include
it :: (a -> b) -> b (bound at <interactive>:51:1)
What do I expect is a return function with one argument.
What does it mean an infinite type?
The error "Occurs check: cannot construct [an] infinite type" results when Haskell determines that a type variable (explicitly given by the programmer or implicitly introduced by Haskell) must satisfy a condition that implies it would need to be recursively defined in terms of itself in a way that would lead to an infinitely "deep" type (i.e., the type variable "occurs" in its own definition).
It normally results from either a typo or conceptual error on the part of the programmer related to confusing two different "levels of structure" in a program.
As a simple example, a list of ints (type [Int]) is a valid Haskell type, and so is a list of lists of ints ([[Int]]) or a list of lists of lists of lists of lists of ints ([[[[[Int]]]]]) but only a finite number of list levels are allowed. You can't have a list of lists of lists of lists of lists, etc. all the way down -- that would be an infinite type. If Haskell thinks you want it to construct such a type, it'll give you an "occurs check" error.
The following definition:
yuck (x:xs) = x == xs
gives this error for exactly this reason. Haskell knows from the left-hand side that yuck takes a list of some unknown element type a where variable x is the head of type a and variable xs is the tail of type [a]. From the RHS, the operator (==) forces x and xs to have the same type -- in other words, it implies the constraint a ~ [a] where the tilde indicates "type equality". No finite type (no type with a finite number of list levels) has this properties, only the invalid infinite type [[[[...forever...]]]] could allow you to remove the outer list level and still have the same type left over, so you get the error.
The issue here is that the programmer has confused two levels of structure: the list xs and an element x.
In your specific example, the reason for the error is similar, but harder to explain. The operator:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
takes two applicative actions with different underlying types: the left-hand side has type given by the applicative functor f applied to the underlying type a -> b; the right-hand side has type given by the same applicative functor f applied to the underlying type b.
You haven't told Haskell which applicative functor f you meant to use, so Haskell tries to infer it. Because the LHS has type:
(+4) :: (Num n) => n -> n
Haskell tries to match the type n -> n with f (a -> b). It may be clearer to write these types using the prefix form of the (->) type operator: Haskell is trying to match (->) n n with f ((->) a b) where f is an applicative functor.
Fortunately, there's an applicative functor instance for (->) t for any type t. So, Haskell reasons that the applicative functor you want is f = (->) n, and it successfully matches (->) n n = f n to f ((->) a b). This implies that n is equal to ((->) a b). Haskell then tries to match the types on the RHS, matching (->) n n = f n with (->) n a = f a. This works, and it implies that n is equal to a.
Now we have a problem. n is simultaneously equal to a -> b (from the LHS) and a (from the RHS). This implies creation of an infinite function type, something that looks like:
(((... forever ...)->b)->b)->b)->b
which is the only way you could remove an outer ...->b and be left with the same type. This is an impossible infinite type, so you get the error.
The underlying problem is that you've made a conceptual error. Given that you are working on a ReaderExample, I think you intended to use the (->) n applicative functor instance, so you and Haskell are in agreement on this point. In this context:
(+4) :: (Num n) -> n -> n
is a reader action that reads a number from the reader and adds four to it. Similarly (+3) is a reader action that reads a number from the reader and adds three to it.
However, (<*>) is an operator that takes a reader action on the LHS that reads from the reader to produce a function (not a number!) that is then applied to the result of using the RHS to read from the reader to produce a number. For example, if you defined:
multiplyByReader :: (Num n) -> n -> n -> n
multiplyByReader readerNum input = readerNum * input
then:
multiplyByReader <*> (+4)
or the simpler version:
(*) <*> (+4)
would make sense. The intended meaning would be: Construct a reader action that (1) uses the LHS to read a number from the reader to create a function that multiplies by the reader; and then (2) applies this function to the number that results from applying the RHS to the reader.
This would be equivalent to \r -> r * (r + 4), as you can see:
> ((*) <*> (+4)) 5 -- same a 5 * (5 + 4)
45
>
When you write (+3) <*> (+4), you're mixing up two different structural levels: the LHS reader yields a number but should instead yield a function that can be applied to a number.
My best guess is that you want to create a reader action that applies (+4) to the reader to get a number and then applies (+3) to that result. In this case, (+3) isn't a reader action; it's just a function you want to apply to the result of the reader action (+4), which is equivalent to fmapping over the reader action:
(+3) <$> (+4)
Of course, you could equivalently write it directly as:
(+3) . (+4)
Both are composite reader actions that add seven to the number read:
> ((+3) <$> (+4)) 5
12
> ((+3) . (+4)) 5
12
>
I'm still a beginner when it comes to Haskell syntax and functional programming languages so when I look at the type declaration for Data.Function.on which is on :: (b -> b -> c) -> (a -> b) -> a -> a -> c, my interpretation is that it takes four parameters: (b -> b -> c), (a -> b), a, a, and returns c. However, when I look at the general use syntax for Data.Function.on which is (*) `on` f = \x y -> f x * f y, it is only taking two function parameters, not four, so how does the type signature relate to the usage syntax?
my interpretation is that it takes four parameters
All Haskell functions take one argument. Some of them just return other functions.
The best way to look at the signature for on is as a higher-order function: (b -> b -> c) -> (a -> b) -> (a -> a -> c). This says "if you give me a binary operator that takes bs and gives a c and a way to get bs from as, I will give you a binary operator that takes as and gives a c". You can see this in the definition:
(*) `on` f = \x y -> f x * f y
The Haskell arrow for function types hides a simple but clever idea. You have to think of -> as an operator, like + and -, but for types. It takes two types as arguments and gives you a new type consisting of a function. So in
Int -> String
You have the types Int and String, and you get a function from an Int to a String.
Just like any other operator, you need a rule for a chain of them. If you think of -, what does this mean?
10 - 6 - 4
Does it mean (10 - 6) - 4 = 0, or does it mean 10 - (6 - 4) = 8? The answer is the first one, which is why we say that - is "left associative".
The -> operator is right associative, so
foo :: Int -> String -> String
actually means
foo :: Int -> (String -> String)
Think about what this means. It means that foo doesn't take 2 arguments and return a result of type String, it actually takes 1 argument (the Int) and returns a new function that takes the second argument (the String) and returns the final String.
Function application works the same way, except that is left associative. So
foo 15 "wibble"
actually means
(foo 15) "wibble"
So foo is applied to 15 and returns a new function which is then applied to "wibble".
This leads to a neat trick: instead of having to provide all the parameters when you call a function (as you do in just about every other programming language), you can just provide the first one or the first few, and get back a new function that expects the rest of the parameters.
This is what is happening with on. I'll use a more concrete version where 'f' is replaced by 'length'.
(*) on length
you give on its first two parameters. The result is a new function that expects the other two. In types,
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
In this case (*) has type Num n => n -> n -> n (I'm using different letters to make this less confusing), so that is matched with the type of the first argument to on, leading to the conclusion that if type b is substitued by n then type c must be as well, and and must also be a Num instance. Therefore length must return some numeric type. As it happens the type of length is [d] -> Int, and Int is an instance of Num, so that works out. So at the end of this you get:
(*) `on` length :: [d] -> [d] -> Int
As an intuitive aid, I read this as "if you give me a comparator of type b, and a way to extract values of type b from values of type a, I will give you a comparator of type a".
E.g. if a is some composite data type and b is some numerical attribute of these data values, you can express the idea of sorting these composite data types by using Data.Function.on.
This question already has answers here:
Understanding Haskell Type Signatures
(3 answers)
Closed 8 years ago.
I need to understand how types works and can be interpreted.
For example, if we take map function we have map :: (a -> b) -> [a] -> [b]
Well, how do I interpret this?
-> is a type constructor for the type of functions. It's a right-associative infix operator, meaning it's grouped together from the right. This means that we can rewrite the type by adding explicit grouping for the functions to the right side.
map :: (a -> b) -> [a] -> [b]
map :: (a -> b) -> ([a] -> [b])
An infix expression for an operator * applied to two arguments, x and y, x * y can be written in prefix notation as (*) a b. We can rewrite the preceding type, starting with the outermost ->, which is the one in the middle.
map :: (->) (a -> b) ([a] -> [b])
And we can now translate the last type into English
map :: (->) (a -> b) ([a] -> [b])
map is a function that takes a "(a -> b)" and returns a "([a] -> [b])"
Where we interpret a -> b ~ (->) a b (here ~ means the types are equivalent) as
(->) a b
function that takes an "a" and return a "b"
And interpret [a] -> [b] ~ (->) [a] [b] as
(->) [ a ] [ b ]
function that takes a list of "a"s and returns a list of "b"s
We say "a function from a to b" as shorthand for "a function that takes an a and returns a b"
The as and bs in the type signature are type variables, they can take on any type, which we call polymorphism. Occasionally, you will see this written explicitly in Haskell as forall So, in all we could say:
map is a polymorphic value for all types a and b which is a function that:
takes a function from a to b and
returns a function from a lists of as to a list of bs.
The fact that this signature contains -> tells us it's a function. Whatever comes after the last -> is the return type of the function once fully applied. Let's look at the individual pieces.
(a -> b)
This is the first argument, and it, too is a function. This means that map is a higher-order-function -- it takes a function as one of its arguments. a -> b itself is a function that transforms some value of type a into some value of type b.
[a]
The second argument. The square brackets is special syntax that denotes list. This argument, therefore, is a list with elements of type a.
[b]
The type of the result. Again, a list, but this time with elements of type b.
We can try to reason about this now. Given a function a -> b and a list of a, map seems to be (it really is) a function that transforms that list of as into a list of bs.
Here's an example: map (*2) [1,2,3]. In this case, a is Integer (or some other integer type) and each element is doubled. b, too, is Integer, because (*2) assumes the same return type, so in the case the type variables a and b are the same. This need not be the case; we could have a different function instead of (*2), say show which would have produced a b distinct from a, namely String.
Try them out in ghci. You can type in map show [1,2,3] directly and see the result. You can query the type of the expression by prepending :t to that line.
To learn more, you should look up one of the marvelous starter resources. LYAH has an entire chapter dedicated to the basic understanding of types, and is definitely worth a read!