4
votes

I'm a beginner of Haskell and I'm trying to divide a list into two sublists with approximate equal size. The module can be loaded but when I tried to run ghci, it does not work.
For example: divideList [1,2,3,4] = [1,2] [3,4] divideList [1,2,3,4,5] = [1,2,3] [4,5]

divideList [] = ([],[])
divideList [x] = ([x],[])

divideList ((x:xs):ys) = if a < b
                         then splitAt (a+1) ((x:xs):ys)
                         else divideList (xs:ys)            
                             where a = length xs
                                   b = length ys 

It said that "No instance for (Num[t0]) arising from the literal '2'". I don't know how to fix it. Can anyone help me??? Thanks!

Here's the error indicated when I typed divideList [2,3,5] in ghci.

<interactive>:2:13:
    No instance for (Num[a0]) arising from literal '2'
    Possible fix: add an instance declaration for (Num[a0])
    In the expression: 2 
    In the first argument of 'divideList', namely "[2,3,5]
    In the expression: divideList [2,3,5]
2
There's no literal 2 in this code, can you post the whole thing? (And the exact error message, with line numbers, etc.)huon
What happens to x when a is equal to or greater than b?Francesco
if a>b then run the "else" partuser2829974

2 Answers

6
votes

First off: Dude, where's my {formatting, type signatures}?

Second: The error you are talking about indicates you have used a numeric literal (ex: 1) in a place where the types say the value should be a list. Because interpreting literals is flexible (polymorphic), the type checker complains that you need to tell it how to interpret a number as list.

Third: The posted code (reformatted and provided a type signature below) does not produce the error you claim.

Fourth: The posted code does not perform the task you describe - the type signature alone is a strong hint - the function you described should take lists to pairs of lists ([a] -> ([a],[a]) but you defined a function that consumes lists of lists ([[a]] -> ([[a]],[[a]]))...

divideList :: [[a]] -> ([[a]], [[a]])
divideList [] = ([],[])
divideList [x] = ([x],[])
divideList ((x:xs):ys) =
    if a < b
      then splitAt (a+1) ((x:xs):ys)
      else divideList (xs:ys)
  where a = length xs
        b = length ys
0
votes

As Thomas says, if you write out the type signature before you write the implementation, it should generally give you a greater feel for what you want your code to be doing.

If I'm correct in understanding your code, you were intending on starting from the left of the provided list, and advancing through until the left-hand side of the list is greater than or equal to in size as the right hand side, at which point you split it.

If this is the case, then there are a couple of bugs in your code:

  1. Your current logic is if a < b then split, where a = length xs (supposed left-hand side) and b = length ys (supposed right-hand side). Assuming you start from the left, the left-hand side will be smaller than the right hand side to begin with! So in this case, you should probably have a > b instead.

  2. Your use of pattern matching is incorrect - (x:xs):ys means "take the first element of the list as (x:xs), which is a single element x plus the rest of the list xs, then the rest as ys". So this pattern matching is trying to turn the first element of the list (2) into a list so it can extract (x:xs) from it, which is where your error is coming from.

If you wish to split the list roughly in half, I would simply do something more like

mySplit list = splitAt ((length list) `div` 2) list

which is much simpler :)