sad_banana_peel
sad_banana_peel

Reputation: 29

Splitting a list on the instance of a specific integer

I'm trying to write a function which would split a list into few separate lists on the instance of one specific integer. Example:

splitlist [3, 4, 0, 6, 0, 7] 0 would return [[3, 4], [6], [7]]

So far I've got:

splitlist :: [Int] -> Int -> [[Int]]
splitlist xs n 
  | length xs == 0 = []
  | head xs == n = [head (tail xs)] : splitlist (tail xs) n 
  | otherwise = [head xs : splitlist (tail xs) n] 

However, I'm getting a type error for head xs in line 5:

    • Couldn't match type ‘[Int]’ with ‘Int’
      Expected type: [Int]
        Actual type: [[Int]]
    • In the second argument of ‘(:)’, namely ‘splitlist (tail xs) n’
      In the expression: head xs : splitlist (tail xs) n
      In the expression: [head xs : splitlist (tail xs) n]
  |
5 |   | otherwise = [head xs : splitlist (tail xs) n]
  |                            ^^^^^^^^^^^^^^^^^^^^^

What am I doing wrong?

Upvotes: 0

Views: 132

Answers (1)

xs has type [Int], so head xs has type Int. splitlist has type [Int] -> Int -> [[Int]], so splitlist (tail xs) n has type [[Int]]. You're trying to call : on those values, which has type a -> [a] -> [a]. The problem is that no choice of a makes that work out: if you pick Int for a, then it's wrong because the second parameter is [[Int]] rather than [Int], and if you pick [Int] for a, then it's wrong because the first parameter is Int rather than [Int].

I think you meant to write [head xs] : splitlist (tail xs) n instead of [head xs : splitlist (tail xs) n], like in the line above that one. However, although this type-checks, it still doesn't work (it produces [[3],[4],[6],[6],[7],[7]] on your test case, and splitlist [0] 0 bottoms).

To actually fix it, let's first rewrite it to look a bit more idiomatic:

splitlist :: [Int] -> Int -> [[Int]]
splitlist [] _ = []
splitlist (x:xs) n
  | x == n = [head xs] : splitlist xs n
  | otherwise = [x] : splitlist xs n

The change I made is that I used pattern-matching in place of testing length and then using head and tail. Now the problems with the logic become apparent:

  • It bottoms if the final element of the list is the separator
  • The result is always a list of only single-element lists
  • There's always one Int in the output for each Int in the input

I assume this is some sort of exercise, so I'm not going to spoil the final answer. However, this should be enough to get you going again.

Upvotes: 1

Related Questions