Question

I'm a haskell newbie, but I'm working on a function I've called mfilter that will exclude elements from a list if they fall into passed-in ranges, like so:

mfilter [(3,7)] [1..10] = [1,2,8,9,10]
mfilter [(10,18), (2,5), (20,20)] [1..25] = [1,6,7,8,9,19,21,22,23,24,25]
mfilter [('0','9')] "Sat Feb 8 20:34:50 2014" = "Sat Feb :: "

In taking the range, I am trying to write a helper function that excludes numbers from these ranges, but I'm running into so many typing problems that I don't know where to start. Here's my code:

mfilter :: Ord a => [(a, a)] -> [a] -> [a]
mfilter (range:t) list = mfilter t (map (exclude range) list)

exclude :: Ord a => (a, a) -> [a] -> [a]
exclude _ [] = []
exclude (first, last) (x:t)
    | x < first && x > last = x : map (exclude (first, last)) t
    | otherwise = map (exclude (first, last)) t

And here are my errors:

Prelude> :l mfilter.hs
[1 of 1] Compiling Main             ( mfilter.hs, interpreted )

mfilter.hs:5:42:
Could not deduce (a ~ [a])
from the context (Ord a)
  bound by the type signature for
             mfilter :: Ord a => [(a, a)] -> [a] -> [a]
  at mfilter.hs:4:12-42
  `a' is a rigid type variable bound by
      the type signature for mfilter :: Ord a => [(a, a)] -> [a] -> [a]
      at mfilter.hs:4:12
Expected type: [a] -> a
  Actual type: [a] -> [a]
In the return type of a call of `exclude'
In the first argument of `map', namely `(exclude range)'
In the second argument of `mfilter', namely
  `(map (exclude range) list)'

mfilter.hs:5:57:
Could not deduce (a ~ [a])
from the context (Ord a)
  bound by the type signature for
             mfilter :: Ord a => [(a, a)] -> [a] -> [a]
  at mfilter.hs:4:12-42
  `a' is a rigid type variable bound by
      the type signature for mfilter :: Ord a => [(a, a)] -> [a] -> [a]
      at mfilter.hs:4:12
Expected type: [[a]]
  Actual type: [a]
In the second argument of `map', namely `list'
In the second argument of `mfilter', namely
  `(map (exclude range) list)'
In the expression: mfilter t (map (exclude range) list)

mfilter.hs:11:44:
Could not deduce (a ~ [a])
from the context (Ord a)
  bound by the type signature for
             exclude :: Ord a => (a, a) -> [a] -> [a]
  at mfilter.hs:8:12-40
  `a' is a rigid type variable bound by
      the type signature for exclude :: Ord a => (a, a) -> [a] -> [a]
      at mfilter.hs:8:12
Expected type: [a] -> a
  Actual type: [a] -> [a]
In the return type of a call of `exclude'
In the first argument of `map', namely `(exclude (first, last))'
In the second argument of `(:)', namely
  `map (exclude (first, last)) t'

mfilter.hs:11:67:
Could not deduce (a ~ [a])
from the context (Ord a)
  bound by the type signature for
             exclude :: Ord a => (a, a) -> [a] -> [a]
  at mfilter.hs:8:12-40
  `a' is a rigid type variable bound by
      the type signature for exclude :: Ord a => (a, a) -> [a] -> [a]
      at mfilter.hs:8:12
Expected type: [[a]]
  Actual type: [a]
In the second argument of `map', namely `t'
In the second argument of `(:)', namely
  `map (exclude (first, last)) t'
In the expression: x : map (exclude (first, last)) t

(and a couple more) I know that it looks like a lot, but these things seem to be related and I can't for the life of me figure out what haskell is trying to tell me with Could not deduce (a ~ [a]) from the context (Ord a)... Any advice for a beginner?

Was it helpful?

Solution

The first argument of map is a -> b, not [a] -> [a]. Therefore, if you want to use map, the type of exclude should be (a, a) -> a -> b

However, I don't see why you would want to use map in the first place. Map projects the list, not filters it. The result of map is always a list of the same length as the original list. Never of a different length.

If you want to filter the list, you should use the filter function. It takes a predicate and a list and returns filtered list:

exclude (first, last) = filter (\x -> x >= first && x <= last)

At the same time, I can see that you were trying to use tail recursion to build the exclude function. If that was your objective, then you shouldn't use map either. Just drop all mentions of map from your code, and it should be good to go:

exclude (first, last) (x:t) =
    | x < first && x > last = x : exclude (first, last) t
    | otherwise = exclude (first, last) t

It is, however, not a good idea to use recursion (unless this is your homework). It's easy to get wrong, and at the same time it's already nicely abstracted for you inside fold (and therefore inside map and filter).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top