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.
In GHCi, doing the following yield:
:t (==)
(==) :: Eq a => a -> a -> Bool
or
:t elem
elem :: (Eq a, Foldable t) => a -> t a -> Bool
I am confused with the arrow going from a to a, and then a to Bool.
Is it because == or elem is a curried function?
The type signature for elem is very similar to ==, except for the additional t. What does t a in :t elem mean?
Yes, operators are curried. Let's ignore the contexts for a second (the part of the type before =>).
(==) :: a -> a -> Bool
(->) associates to the right, so this means:
(==) :: a -> (a -> Bool)
That is, it's a function which, given an a, returns another function, which in turn takes an a and gives a Bool. It returns the function which is only true when its argument is equal to the first a.
(We will set NoMonomorphismRestriction because otherwise it will just be extra confusing for no good reason)
ghci> :set -XNoMonomorphismRestriction
ghci> let f = (==) 1
ghci> f 1
True
ghci> f 2
False
-- or just
ghci> (==) 1 2
False
The part before the (=>) puts constraints on types. Eq a means that a must be a type that supports equality.
As for the t in elem, that might be a bit advanced for you to understand fully right now. I'll give you a little bit. Because of the context
(Eq a, Foldable t) => ...
we know that t has to be Foldable. Lists are foldable, and foldable doesn't mean much more than "has a toList method". So you can read elem as:
elem :: (Eq a) => a -> [a] -> Bool
and in general, when you see a foldable type, just pretend it's a list.
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.
I’m trying to learn Haskell and I was trying to create a function that takes a list of lists and groups the sublist by equivalent sums. This is not homework.
import Data.List
let x = [[1,2],[2,1],[5,0],[0,3],[1,9]]
let groups = groupBy (\i j -> sum i == sum j) x
I get this output in GHCi:
[[[1,2],[2,1]],[[5,0]],[[0,3]],[[1,9]]]
I get [[1,2],[2,1]] grouping together, but not with [0,3]. Why is this?
I suspect I need to use map, but I can’t seem to make it work.
The groupBy function preserves the input order and is thus invertible. If you’re willing to throw away that information, you could use code along the lines of
import Data.List (foldl')
import Data.Map (elems,empty,insertWith')
bucketBy :: Ord b => (a -> b) -> [a] -> [[a]]
bucketBy eq = elems . foldl' go empty
where go m l = insertWith' (++) (eq l) [l] m
In action:
*Main> bucketBy sum x
[[[0,3],[2,1],[1,2]],[[5,0]],[[1,9]]]
How it works
The application of elems from Data.Map gives a clue for what’s happening.
elems :: Map κ α -> [α]
O(n). Return all elements of the map in the ascending order of their keys.
elems (fromList [(5,"a"), (3,"b")]) == ["b","a"]
elems empty == []
Mapping
A Map associates values of some type κ with values of another possibly distinct type α. In the example from your question, you start with x whose type is
*Main> :type x
x :: [[Integer]]
That is, x is a list of integer lists. The type of the resulting partition of x you want is
*Main> :t [[[0,3],[2,1],[1,2]],[[5,0]],[[1,9]]]
[[[0,3],[2,1],[1,2]],[[5,0]],[[1,9]]] :: Num τ => [[[τ]]]
or a list of lists where each of the latter lists are themselves lists that all have the same sum. The Num τ => bit is a context that constrains the type τ to be an instance of the typeclass Num. Happy for us, Integer is such a type:
*Main> :info Integer
data Integer
…
instance Num Integer -- Defined in GHC.Num
…
We know then that the type of the partition is [[[Integer]]]. This typeclass nonsense may seem unnecessarily fussy, but we’ll need the concept again in just a moment. (To give you an idea of what’s going on, the typechecker doesn’t have enough information to decide whether the literal 0, for example, is of type Int or Integer.)
Each sublist contains lists with the same sum. In other words, there exists a mapping from a sum to a list of integer lists. Therefore, the type of the Map used in bucketBy must resemble
Map Integer [[Integer]]
For example, with the sum 3 we associate the list
[ [0,3]
, [2,1]
, [1,2]
]
The fold recursion pattern
Folding is a highly general pattern. Left fold, foldl and friends in Haskell lets you “insert” an operator between elements of a list beginning with the zero value at the left end of the list. For example, the sum of [5,3,9,1] expressed as a left fold is
((((0 + 5) + 3) + 9) + 1)
or
foldl (+) 0 [5,3,9,1]
That is, beginning with a base value of zero, we successively add elements of the list and accumulate the sum.
Recall the definition of bucketBy contains
elems . foldl' go empty
This means the result of the left fold must be of type Map Integer [[Integer]], the zero value for our fold is the empty Map of that type, and go is somehow adding each successive value of a list into the map.
Note that foldl' is the strict cousin of foldl, but strictness is beyond the scope of this answer. (See also “Stack overflow” on HaskellWiki.)
Dude, where’s my list?
Given the type of foldl'
*Main> :t foldl'
foldl' :: (a -> b -> a) -> a -> [b] -> a
we should have three arguments in the application, but only two are present in the code above. This is because the code is written in point-free style. Your list is there implicitly due to partial application of foldl'.
Think back to the sum-as-fold example above. The type of that application without the final argument is
*Main> :t foldl (+) 0
foldl (+) 0 :: Num b => [b] -> b
Partial application allows us to create new functions. Here we defined a function that computes a number from some list of numbers. Hmm, sounds familiar.
*Main> :t sum
sum :: Num a => [a] -> a
The . combinator expresses function composition. Its name is chosen to resemble the notation g∘f as commonly seen in mathematics textbooks to mean “do f first and then compute g from the result.” This is exactly what’s happening in the definition of bucketBy: fold the list of values into a Map and then get the values of out the Map.
If ya gotta go, go with a smile
In your comment, you asked about the purpose of m. With an explicit type annotation, we might define go as
...
where go :: Map Integer [[Integer]] -> [Integer] -> Map Integer [[Integer]]
go m l = insertWith' (++) (eq l) [l] m
Matching variables with types, m is the Map we’ve accumulated so far, and l is the next Integer list that we want to toss into the appropriate bucket. Recall that eq is an argument to the outer bucketBy.
We can control how a new item goes into the map using insertWith'. (By convention, functions whose names end with trailing quotes are strict variants.)
The (++) combinator appends lists. The application eq l determines the appropriate bucket for l.
Had we written l rather than [l], the result would want to be
*Main> bucketBy sum x
[[0,3,2,1,1,2],[5,0],[1,9]]
but then we lose the structure of the innermost lists.
We’ve already constrained the type of bucketBy's result to be [[[α]]] and thus the type of the Map's elements. Say the next item l to fold is [1,2]. We want to append, (++), it to some other list of type [[Integer]], but the types don’t match.
*Main> [[0,3],[2,1]] ++ [1,2]
<interactive>:1:21:
No instance for (Num [t0])
arising from the literal `2'
Possible fix: add an instance declaration for (Num [t0])
In the expression: 2
In the second argument of `(++)', namely `[1, 2]'
In the expression: [[0, 3], [2, 1]] ++ [1, 2]
Wrapping l gets us
*Main> [[0,3],[2,1]] ++ [[1,2]]
[[0,3],[2,1],[1,2]]
Generalizing further
You might stop with
bucketBy :: ([Integer] -> Integer) -> [[Integer]] -> [[[Integer]]]
bucketBy eq = elems . foldl' go empty
where go m l = insertWith' (++) (eq l) [l] m
or even
bucketBy :: ([Integer] -> Integer) -> [[Integer]] -> [[[Integer]]]
bucketBy eq = elems . foldl' go empty
where go :: Map Integer [[Integer]] -> [Integer] -> Map Integer [[Integer]]
go m l = insertWith' (++) (eq l) [l] m
and be perfectly happy because it handles the case from your question.
Suppose down the road you have a different list y defined as
y :: [[Int]]
y = [[1,2],[2,1],[5,0],[0,3],[1,9]]
Even though the definition is very nearly identical to x, bucketBy is of no use with y.
*Main> bucketBy sum y
<interactive>:1:15:
Couldn't match expected type `Integer' with actual type `Int'
Expected type: [[Integer]]
Actual type: [[Int]]
In the second argument of `bucketBy', namely `y'
In the expression: bucketBy sum y
Let’s assume you can’t change the type of y for some reason. You might copy-and-paste to create another function, say bucketByInt, where the only change is replacing Integer with Int in the type annotations.
This would be highly, highly unsatisfying.
Maybe later you have some list of strings that you want to bucket according to the length of the longest string in each. In this imaginary paradise you could
*Main> bucketBy (maximum . map length) [["a","bc"],["d"],["ef","g"],["hijk"]]
[[["d"]],[["ef","g"],["a","bc"]],[["hijk"]]]
What you want is entirely reasonable: bucket some list of things using the given criterion. But alas
*Main> bucketBy (maximum . map length) [["a","bc"],["d"],["ef","g"],["hijk"]]
<interactive>:1:26:
Couldn't match expected type `Integer' with actual type `[a0]'
Expected type: Integer -> Integer
Actual type: [a0] -> Int
In the first argument of `map', namely `length'
In the second argument of `(.)', namely `map length'
Again, you may be tempted to write bucketByString, but by this point, you’re ready to move away and become a shoe cobbler.
The typechecker is your friend. Go back to your definition of bucketBy that’s specific to Integer lists, simply comment out the type annotation and ask its type.
*Main> :t bucketBy
bucketBy :: Ord k => (b -> k) -> [b] -> [[b]]
Now you can apply bucketBy for the different cases above and get the expected results. You were already in paradise but didn’t know it!
Now, in keeping with good style, you provide annotations for the toplevel definition of bucketBy to help the poor reader, perhaps yourself. Note that you must provide the Ord constraint due to the use of insertWith', whose type is
insertWith' :: Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
You may want to be really explicit and give an annotation for the inner go, but this requires use of the scoped type variables extension.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.List (foldl')
import Data.Map (Map,elems,empty,insertWith')
bucketBy :: forall a b. Ord b => (a -> b) -> [a] -> [[a]]
bucketBy eq = elems . foldl' go empty
where go :: Map b [a] -> a -> Map b [a]
go m l = insertWith' (++) (eq l) [l] m
Without the extension and with a type annotation of
bucketBy :: Ord b => (a -> b) -> [a] -> [[a]]
the typechecker will fail with errors of the form
Could not deduce (b ~ b1)
from the context (Ord b)
bound by the type signature for
bucketBy :: Ord b => (a -> b) -> [a] -> [[a]]
at prog.hs:(10,1)-(12,46)
`b' is a rigid type variable bound by
the type signature for
bucketBy :: Ord b => (a -> b) -> [a] -> [[a]]
at prog.hs:10:1
`b1' is a rigid type variable bound by
the type signature for go :: Map b1 [a1] -> a1 -> Map b1 [a1]
at prog.hs:12:9
In the return type of a call of `eq'
In the second argument of `insertWith'', namely `(eq l)'
In the expression: insertWith' (++) (eq l) [l] m
This is because the typechecker treats the b on the inner type annotation as a distinct and entirely unrelated type b1 even though a human reader plainly sees the intent that they be the same type.
Read the scoped type variables documentation for details.
One last small surprise
You may wonder where the outer layer of brackets went. Notice that the type annotation generalized from
bucketBy :: ([Integer] -> Integer) -> [[Integer]] -> [[[Integer]]]
to
bucketBy :: forall a b. Ord b => (a -> b) -> [a] -> [[a]]
Note that [Integer] is itself another type, represented here as a.
groupBy splits the list into chunks of adjacent elements satisfying the given predicate. Since in your case, the [0,3] is separated from the [1,2] and [2,1], the first group includes only these. To collect all elements of the list having the same sum into one group, you need some preprocessing, e.g. with sortBy.
import Data.List
import Data.Function
import Data.Ord
groupBySum :: Num a => [[a]] -> [[[a]]]
groupBySum xss = groups
where
ys = map (\xs -> (sum xs,xs)) xss
sortedSums = sortBy (comparing fst) ys
groupedSums = groupBy ((==) `on` fst) sortedSums
groups = map (map snd) groupedSums
From hackage:
The group function takes a list and returns a list of lists such that the concatenation of the result is equal to the argument.
groupBy is the same, except that you can specify your equality test. Thus, since in your input list [0,3] is not adjacent to [1,2] or [2,1], it is put on its own.
Apparently, my type signature was off. I've since found out why. Now, I'm interested in knowing more about the GHCI inferred signature on my typo. I was trying to get this code to work:
elemNum :: (Eq a, Num b) => a -> [a] -> b
elemNum e l = f e l
where f _ [] = [] -- this was my typo, supposed to read 0
f e (x:xs)
| x == e = 1 + f e xs
| otherwise = f e xs
It obviously doesn't work for the reason noted above; but, if I remove my signature it compiles (not sure why, please explain), and I get this signature:
elemNum :: (Num [a], Eq t) => t -> [t] -> [a]
I've never seen the typeclass Num [a] before.. What does that mean, and how does it compare to (Num a) => [a].
Num a means that the type a can be treated as a number; eg. you can add two as together to get a new a or you can negate an a and get an a. Integer and Double fall into this category.
Correspondingly, Num [a] means that the type [a] can be treated as a number. I.e. you can add together two lists of a to get a new list of a. This is very unlikely to be meaningful because no lists are numbers (by default). It means that you are treating a list like it is a number, causing GHC to conclude that you must want your list to act like a number, and thus adding an appropriate constraint.
Such a constraint might arise from a function like:
foo (x:xs) = xs + 1
xs is pattern matched as the tail of a list, and thus is itself a list, and then you are adding to it, treating the list as a number.
Num [a] constraint means that list is instance of Num type class.
foo :: Num a => [a]
is list of values which are instances of Num type class
bar :: Num [a] => [a]
is list of values which is instance of Num type class by itself. This means that you can use all functions from Num and construct lists from numeric literals so following code is valid although requires FlexibleContexts
bar :: Num [a] => [a]
bar = 42
P.S. You don't need helper function here. elemNum e l = f e l ⇒ elemNum = f. So you can write your function as
elemNum _ [] = 0
elemNum e (x:xs)
| x == e = 1 + f e xs
| otherwise = f e xs