Variable not in scope in nested where

Viewed 242

I'm implementing luhn algorithm, here's the code I have so far:

luhn :: [Int] -> Bool
luhn xs = ((evens + odds) `mod` 10) == 0 where
      evens = sum [x | (x,i) <- reversed_indexed_xs, i `mod` 2 == 0]
      odds = sum [luhnDouble x | (x,i) <- reversed_indexed_xs, i `mod` 2 /= 0] where
            reversed_indexed_xs = zip (reverse xs) [0..]

error I'm getting is

 Variable not in scope: reversed_indexed_xs :: [(a, Integer)]
   |
33 |       evens = sum [x | (x,i) <- reversed_indexed_xs, i `mod` 2 == 0]
   |                                 ^^^^^^^^^^^^^^^^^^^
Failed, 0 modules loaded.

despite reversed_indexed_xs being defined in nested where statement. I assume my problem is with indentation, any help?

3 Answers

You don't need another nested where, just do

luhn :: [Int] -> Bool
luhn xs = ((evens + odds) `mod` 10) == 0 where
      evens = sum [x | (x,i) <- reversed_indexed_xs, i `mod` 2 == 0]
      odds = sum [luhnDouble x | (x,i) <- reversed_indexed_xs, i `mod` 2 /= 0]
      reversed_indexed_xs = zip (reverse xs) [0..]

The problem is that when you write X where Y, the definitions in Y can be used only in the expression X. In your case, reversed_indexed_xs can be used only in the scope of the definition of odds.

You scoped the where with the odds statement, not the even:

luhn :: [Int] -> Bool
luhn xs = ((evens + odds) `mod` 10) == 0 where
      evens = sum [x | (x,i) <- reversed_indexed_xs, i `mod` 2 == 0]
      odds = sum [luhnDouble x | (x,i) <- reversed_indexed_xs, i `mod` 2 /= 0] where
            reversed_indexed_xs = zip (reverse xs) [0..]

Since the reversed_indexed_xs uses no variables bounded to odds, we can simply put it on the same level as evens and odds:

luhn :: [Int] -> Bool
luhn xs = ((evens + odds) `mod` 10) == 0 where
      evens = sum [x | (x,i) <- reversed_indexed_xs, i `mod` 2 == 0]
      odds = sum [luhnDouble x | (x,i) <- reversed_indexed_xs, i `mod` 2 /= 0]
      reversed_indexed_xs = zip (reverse xs) [0..]

The nested where is scoped only to the definition under which it's nested - i.e. to odds, - but you're using it in both evens and odds. It's in scope for odds, but not for evens.

To use it in both evens and odds, you can just define it at the same level, no nesting required:

luhn :: [Int] -> Bool
luhn xs = ((evens + odds) `mod` 10) == 0 where
      evens = sum [x | (x,i) <- reversed_indexed_xs, i `mod` 2 == 0]
      odds = sum [luhnDouble x | (x,i) <- reversed_indexed_xs, i `mod` 2 /= 0]
      reversed_indexed_xs = zip (reverse xs) [0..]
Related