I've just started programming in Haskell, and I am solving 99 Haskell problems, and when I was nearly done with 10th, I've encountered this problem:
-- Exercise 9
pack :: Eq a => [a] -> [[a]]
pack [] = []
pack list = let (left,right) = span (== head list) list in
left : pack right
-- Exercise 10
encode :: (Eq a, Integral c) => [a] -> [(c, a)]
encode [] = []
encode list = map (\x -> (length x, head x)) (pack list)
-- this doesn't work ^^^^^^^^
The error produced told me that
Could not deduce (c ~ Int)
from the context (Eq a, Integral c)
bound by the type signature for
encode :: (Eq a, Integral c) => [a] -> [(c, a)]
at C:\fakepath\ex.hs:6:11-47
`c' is a rigid type variable bound by
the type signature for
encode :: (Eq a, Integral c) => [a] -> [(c, a)]
at C:\fakepath\ex.hs:6:11
In the return type of a call of `length'
In the expression: length x
In the expression: (length x, head x)
I've managed to fix that by inserting a function I've read about in Learn you a Haskell: fromIntegral.
encode list = map (\x -> (fromIntegral $ length x, head x)) (pack list)
So, my question is, why is that needed?
I've run :t length and got [a] -> Int, which is a pretty defined type for me, which should satisfy Integral c constraint.
The type signature (Eq a, Integral c) => [a] -> [(c, a)] means the function works for any types a and c in the appropriate typeclasses. The actual type used is specified at the call site.
As a simple example, let's take a look at the type of the empty list:
:t []
[a]
What this means is that [] represents an empty list of String, and empty list of Int, an empty list of Maybe [Maybe Bool] and whatever other types you can imagine. We can imagine wrapping this in a normal identifier:
empty :: [a]
empty = []
empty obviously works the same way as []. So you can see that the following definition would make no sense:
empty :: [a]
empty = [True]
after all, [True] can never be a [Int] or [String] or whatever other empty list you want.
The idea here is the same, except we have typeclass constraints on the variables as well. For example, you can use encode to return a [(Integer, String)] list because Integer is also in the Integral class.
So you have to return something polymorphic that could be any Integral--just what fromIntegral does. If you just returned Int, encode would only be usable as an Int and not any Integral.
Related
I am a Haskell newbie trying to wrap my head around type binding in functions and how Haskell enforces it. For example, even though the type for the fst function is fst :: (a, b) -> a, the compiler does not complain for the function fst'. But the compiler complains about type bindings for the function elem'.
fst' :: (a,a) -> a
fst' s = fst s
elem' :: (Eq a, Eq b) => a -> [b] -> Bool
elem' x xs = elem x xs
fst has as type fst :: (a, b) -> a so that means it is fine to define a function:
fst' :: (a, a) -> a
fst' = fst
Your fst' function is more restrictive than the fst function. Regardless with what you replace a in your fst' function that is fine for fst. If for example a ~ Bool holds, then you call fst with signature fst :: (Bool, Bool) -> Bool. But since fst can deal with all as and b, it is fine that both elements of the tuple are Bool, so given fst can handle tuples for all possible types for both the first and the second item of the 2-tuple, it is defintely ok if the two items have the same type.
The latter is not ok, here you define:
elem' :: (Eq a, Eq b) => a -> [b] -> Bool
elem' = elem
but elem has type elem :: Eq a => a -> [a] -> Bool. The signatures you can make with the elem' function are not a subset of the ones of the elem function, since you can set a ~ Int and b ~ Bool. In that case you expect elem :: Int -> [Bool] -> Bool, but evidently that does not hold, since the Int and Bool type are two different types, and in the elem signature, these are both as.
I just see an expression
fmap_List :: (a -> b) -> [] a -> [] b
-- "[] a" means "[a]", for types.
fmap_List f [] = []
fmap_List f (x:xs) = f x : fmap_List f xs
Since [] a means [a], why we don't put [a] directly instead? Are there some special cases we should use [] a?
It’s just avoiding the syntactic sugar [a] as a way of illustrating that the f type parameter of fmap :: Functor f => (a -> b) -> f a -> f b is being replaced with the type constructor [], just like any other type constructor.
That is, you might write the type [a] as [] a when you want to emphasise the relationship to a signature that’s polymorphic over some type constructor, like fmap:
fmap :: Functor f => (a -> b) -> f a -> f b
-- f = []
fmap_List :: (a -> b) -> [] a -> [] b
fmap_List = fmap
-- f = Maybe
fmap_Maybe :: (a -> b) -> Maybe a -> Maybe b
fmap_Maybe = fmap
Or join:
join :: Monad m => m ( m a) -> m a
join_List :: [] ([] a) -> [] a
This is exactly the same as [[a]] -> [a], just making it clearer that m = [].
[] a is the type constructor [] applied to the type variable a. [] a or [a] has the kind *, the kind of types that are inhabited by values, such as Int, Char, Maybe Int, or Either String Int. [] has kind * -> *, the kind of types that take a type argument and produce a type as a result, such as [], Maybe, Identity, or Either e.
You can see this for example in the definition of instance Monad []—we’re giving the constructor [] (of kind * -> *) as an argument to Monad (of kind (* -> *) -> Constraint), not a type (of kind *) made with that constructor such as instance Monad ([] a). This is just like using Maybe instead of Maybe a, Maybe Int, Maybe String, &c.
Using the TypeApplications pragma, you can explicitly apply polymorphic functions to type arguments, e.g. in GHCi:
> :set -XTypeApplications
> :type fmap #[]
fmap #[] :: (a -> b) -> [a] -> [b]
> :type fmap #Maybe
fmap #Maybe :: (a -> b) -> Maybe a -> Maybe b
> :type fmap #[] #Int #Char
fmap #[] #Int #Char :: (Int -> Char) -> [Int] -> [Char]
> :type fmap #[] #_ #Bool
fmap #[] #_ #Bool :: (a -> Bool) -> [a] -> [Bool]
This is very useful for figuring out how to use polymorphic functions, or documenting which container or monad you’re using such a function with, by specialising a type to a (more) concrete instance:
> :type traverse
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
> :type traverse #[] #IO
traverse #[] #IO :: (a -> IO b) -> [a] -> IO [b]
And you can also ask GHCi for the kind of a type to get a better understanding of kinds:
> :kind Either
Either :: * -> * -> *
> :kind Either String
Either String :: * -> *
> :kind Either String Int
Either String Int :: *
> :kind []
[] :: * -> *
> :kind [] Int
[] Int :: *
> :kind [Int]
[Int] :: *
> :kind Functor
Functor :: (* -> *) -> Constraint
> :kind Num
Num :: * -> Constraint
The notation [] is useful when it is not being applied but passed to another type constructor.
Fix [] -- recursion-schemes
Free [] a -- free
ReaderT r [] a -- transformers
Compose [] Maybe a -- base (Data.Functor.Compose)
Since [] a means [a], why we don't put [a] directly instead?
This is a funny question. Let me try to convince you that, arguably, the real question is:
Since [a] means [] a, why we don't put [] a directly instead?
Consider the following parametric types:
data Identity a = Identity a
data Maybe a = Nothing | Just a
data HPair a = HPair a a
data HTriple a = HTriple a a a
data Tree a = Empty | Branch (Tree a) a (Tree a)
data List a = Nil | Cons a (List a)
data [a] = [] | (a : [a])
Note that all of these have the form TypeConstructor a, except for [a]! Indeed, to make the world more coherent, we should actually write [] a instead of [a].
This also makes it clear that [] is a type constructor, exactly like Identity, Maybe, Tree, ....
The syntax [a] is convenient, and possibly easier to read, especially for a beginner. However, it makes understanding the real nature of [] harder. Maybe has no such issue, by comparison.
I am reading the book "Programming in Haskell". One exercise asks me to define map f using an higher-order function. I choose to define map (+1) like the following:
unfold p h t x | p x = []
| otherwise = h x : unfold p h t (t x)
-- equivalent to `map (+1)`
mapinc = unfold (==[]) ((+1).head) tail
(Taken straight from the exercise question) The function unfold p h t produces the empty list if the predicate p is true of the argument value, and otherwise produces a non-empty list by applying the function h to this value to give the head, and the function t to generate another argument that is recursively processed in the same way to produce the tail of the list.
I have checked my implementation of mapinc and it looks fine:
*Main> mapinc [1,2,3]
[2,3,4]
However, after I add the type declaration:
mapinc :: Num a => [a] -> [a]
mapinc = unfold (==[]) ((+1).head) tail
Then reload the script in WinGHCi, it gives the following error:
• Could not deduce (Eq a) arising from a use of ‘==’
from the context: Num a
bound by the type signature for:
mapinc :: forall a. Num a => [a] -> [a]
at D:\7a.hs:4:1-29
Possible fix:
add (Eq a) to the context of
the type signature for:
mapinc :: forall a. Num a => [a] -> [a]
• In the first argument of ‘unfold’, namely ‘(== [])’
In the expression: unfold (== []) ((+ 1) . head) tail
In an equation for ‘mapinc’:
mapinc = unfold (== []) ((+ 1) . head) tail
|
5 | mapinc = unfold (==[]) ((+1).head) tail | ^^^^
Any clue why it happens?
Your signature is too broad. The predicate you have written is == []. Haskell can only check if two lists are equal, if the elements of the list can be checked as well. In the source code we see something like:
instance Eq a => Eq [a] where
...
Yes, here we will never check the equality of two items, since we check with the empty list, but the compiler of course does not know that: it simply sees that in order to check whether two lists are equal, we need to be able to check if elements are equal.
The Num typeclass does not imply that the type is also an Eq type. We can do two things here:
add the Eq type constraint to the signature:
mapinc :: (Eq a, Num a) => [a] -> [a]
mapinc = unfold (==[]) ((+1).head) tail
more elegant: do not rely on the fact that we need to be able to compare elements, but use null :: [a] -> Bool instead (a function that checks if the list is empty):
mapinc :: Num a => [a] -> [a]
mapinc = unfold null ((+1).head) tail
I have managed to implement a mock filter functions (after lots of attempts)
filter' :: (Num a, Eq a) => (a -> Bool) -> [a] -> [a]
filter' a [] = []
filter' a (x:xs) = if a x
then x : filter' a xs
else filter' a xs
What I don't clearly understand is the type declaration
filter' :: (Num a, Eq a) => (a -> Bool) -> [a] -> [a]
-- filter' (<10) [1,2,3]
-- output = []
We pass in (<10) [1,2,3]. However in the type declaration (a -> Bool) we pass in a which comes from the list recursively and the output is either true or false. However what about the expressing the test (<10)? Why don't we add another Bool?
The type of your filter' function is only so constrained because you've declared that it is. If you don't declare the type, the compiler will infer a more tolerant type: (a -> Bool) -> [a] -> [a]. This is the same type as the built-in filter function:
Prelude> :type filter
filter :: (a -> Bool) -> [a] -> [a]
The expression (< 10) is a so-called section. It's a partially applied function.
The operator < is itself a function:
Prelude> :type (<)
(<) :: Ord a => a -> a -> Bool
You can read this as: < is a function that takes two arguments, both of the generic type a. The type a must belong to the typeclass Ord. When you call < with such two values, a Bool value is returned.
Since Haskell functions are curried, you can call a function with only some of the arguments. The return value is a new function that 'waits for the remaining arguments':
Prelude> :type (< 10)
(< 10) :: (Num a, Ord a) => a -> Bool
This type is a little more constrained, because the literal 10 is inferred to belong to the Num typeclass. Since < is in use, the original constraint for that (Ord) is still in effect as well.
The expression [1,2,3] is is by the compiler inferred as:
Prelude> :type [1,2,3]
[1,2,3] :: Num t => [t]
The values all belong to the Num typeclass. When you use all of these types together, you get the union of all the inferred types:
Prelude> :type filter (< 10) [1,2,3]
filter (< 10) [1,2,3] :: (Num a, Ord a) => [a]
The Num typeclass is inferred because of the use of literals, and the Ord typeclass is inferred because of the use of the < operator.
I'm playing with some Haskell code. I've defined two functions:
count :: [a] -> Int
count [] = 0
count (x:xs) = 1 + (count xs)
-- 03. Write a function that computes the mean of a list, i.e., the sum of all
-- elements in the list divided by its length. (You may need to use the
-- fromIntegralfunction to convert the length of the list from an integer
-- into a floating-point number.)
-- I've guessed this type definition, but it's incorrect:
-- listMean :: [a] -> Double
-- The following is the same inferred by hgci
listMean :: (Fractional a) => [a] -> a
listMean lst = (foldl1 (+) lst)/(fromIntegral (count lst))
Why [a] -> Double is not correct? It seems that I give lst that is a generic list of some type a and listMean returns a Double. What am I doing wrong?
Thanks,
Alfredo
First of all, listMean :: [a] -> Double says that listMean is a function taking a list of any type a to a single Double value.
But you rely on being able to apply (+) to the elements of the list (foldl1 (+)), which requires that the type a be an instance of Num, which means you have at least:
listMean :: (Num a) => [a] -> b
You also apply (/) to the value of type a that results from the foldl1 operation. To do so, a must not only be an instance of Num, but of Fractional. Applying this requirement to the type a gives the type signature:
listMean :: (Fractional a) => [a] -> b
Now, what of b? Well, the signature for (/) is (/) :: (Fractional a) => a -> a -> a. So, the result of listMean must also be an instance of Fractional. Further, it must be the same instance of Fractional as that contained in the list: type b is thus, in fact, type a, and listMean's most general signature is:
listMean :: (Fractional a) => [a] -> a
This is exactly what the compiler inferred. If you want to specialize this for Double, you would have to replace both occurrences of a with Double:
listMean :: [Double] -> Double
This is because you have no operator in there that will coerce any instance of Fractional into a Double, so both input and output to (/) must be of type Double.