1

I am trying to take the sum of a list in Haskell but it gives the error, please see the below code.

binListToDec :: [Int] -> Int
binListToDec (x:xs) = if length binListToDec == 0 then 1
                      else x + binListToDec xs

It gives the following error

 * No instance for (Foldable ((->) [Int]))
        arising from a use of `length'
    * In the first argument of `(==)', namely `length binListToDec'
      In the expression: length binListToDec == 0
      In the expression:
        if length binListToDec == 0 then 1 else x + binListToDec xs
  |
2 | binListToDec (x:xs) = if length binListToDec == 0 then 1
3
  • What is length binListToDec supposed to do? Commented Nov 13, 2018 at 18:14
  • take the length of the string passed to the function. and if its 0 ( empty) then return 1 as the sum @WillemVanOnsem Commented Nov 13, 2018 at 18:15
  • 5
    but (a) the list you pass is (x:xs) and (b) the length can never be zero, since (x:xs) is the pattern for a non-empty list. Commented Nov 13, 2018 at 18:16

1 Answer 1

3

Among the myriad ways you could write this, two possibilities would be

binListToDec xs = if length xs == 0 then 0  -- see below
                  else (head xs) + binListToDec (tail xs)

and

binListToDec [] = 0
binListToDec (x:xs) = x + binListToDec xs

You appear to be trying to combine bits of each. There's no way to write a single pattern that matches simultaneously 1) an empty list and 2) a non-empty list with 3) its head and tail matched separately.

  • xs matches 1) and 2).
  • all@(x:xs) matches 2) and 3)
  • 1) and 3) cannot be matched, because the pairing is nonsensical: an empty list doesn't have a separate head and tail. [] and (x:xs) match lists from two non-overlapping sets of possible list values.

    Update: there is a lazy pattern match all@(~(x:xs)). The tilde prevents the match (x:xs) from being attempted until there is a need to evaluate x or xs. We think of

    binListToDec all@(~(x:xs)) = if length all == 0 then 0 else x + binListToDec
    

    as equivalent to

    binListToDec all = if length all == 0 
                       then 0
                       else let (x:xs) = all 
                            in x + binListToDec
    

    A lazy pattern match can still fail, but here we defer using x and xs until we know it won't.


length binListToDec attempts to compute the length of the function itself, not the length of its argument, in your attempt. The correct argument for length is used above. Also, the generally accepted sum of an empty list is 0, not 1.

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

2 Comments

all@(~(x:xs)) meets all three criteria. ...but that's not to say I recommend it. Just that it's possible. e.g. binListToDec all@(~(x:xs)) = if length all == 0 then 0 else x + binListToDec xs would work, though it would be slow for all the same reasons your first solution is.
@DanielWagner Thanks; I figured there was some bit of syntax I was forgetting about.

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.