1

I'm trying to use map to return a list of lists. But i keep getting an error. I know map takes in a function and then uses that function. But i keep getting an error on it.

map (take 3) [1,2,3,4,5]

This is supposed to return [[1,2,3],[2,3,4],[3,4,5]], but it returns this error

<interactive>:6:1: error:
• Non type-variable argument in the constraint: Num [a]
  (Use FlexibleContexts to permit this)
• When checking the inferred type
    it :: forall a. Num [a] => [[a]]

is it hitting null is that why?

6
  • map (take 3) (take 3 (tails [1,2,3,4,5])) Commented Oct 27, 2017 at 3:53
  • wait, what's going on here? and this returns the same error Commented Oct 27, 2017 at 3:59
  • 1
    map only passes one item at a time to each call of the mapping function, not a sublist. My code uses tails followed by take 3 in order to get the first 3 sublists. Commented Oct 27, 2017 at 4:05
  • it still results as an error Commented Oct 27, 2017 at 4:11
  • It works for me. Commented Oct 27, 2017 at 4:16

1 Answer 1

8

Let's take a look at exactly what the error message is saying.

map (take 3) [1, 2, 3, 4, 5]

map's type signature is

map :: (a -> b) -> [a] -> [b]

So it takes a function from a to b and returns a function from [a] to [b]. In your case, the function is take 3, which takes a list and returns a list. So a and b are both [t]. Therefore, the second argument to map should be [[t]], a list of lists. Now, Haskell looks at the second argument and sees that it's a list of numbers. So it says "How can I make a number into a list?" Haskell doesn't know of any good way to do that, so it complains that it doesn't know any type Num [t].

Now, as for what you meant to do, I believe it was mentioned in the comments. The tails function1 takes a list and returns the list of all tails of that list. So

tails [1, 2, 3, 4, 5]
-- ==> [[1, 2, 3, 4, 5], [2, 3, 4, 5], [3, 4, 5], [4, 5], [5], []]

Now you can apply the take function to each argument.

map (take 3) (tails [1, 2, 3, 4, 5])
-- ==> [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5], [5], []]

Oops! We've got some extra values we don't want. We only want the values that have three elements in them. So let's filter out the ones we don't want. filter takes a predicate (which is just a fancy way of saying "a function that returns a Boolean) and a list and returns a list containing only the elements that satisfy the predicate. The predicate we want is one that takes a list and returns whether or not that list has three elements.

\x -> ...           -- We want only the lists
\x -> length x ...  -- whose length
\x -> length x == 3 -- is exactly equal to 3

So that's our function. Now we pass that to filter.

filter (\x -> length x == 3) (map (take 3) (tails [1, 2, 3, 4, 5]))
-- ==> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]

[1] Note that you may need to import Data.List to get the tails function.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the detailed answer
Filtering like that is much slower than just using take 3 again as 4castle suggested.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.