views:

212

answers:

4

I'm struggling with this code right now. I want to determine whether an integer is divsible by 11. From what I have read, an integer is divisible to 11 when the sum (one time +, one time -) of its digits is divisible by 11.

For example: 56518 is divisible by 11, because 8-1+5-6+5 = 11, and 11 is divisible by 11.

How can i write this down in Haskell? Thanks in advance.

+4  A: 

A number x is divisible by y if it's remainder when divided by y is 0. So you can just do

divisibleBy11 x = x `rem` 11 == 0
sepp2k
thank you very very much. is there any other way to get the same result?
marco
@ifan: Yes, quite a few. Most trivially you could replace `rem` by `mod`. You could also create a list or set containing all multiples of 11 and then check whether the number is in there or you could use the rule you mentioned in your question, but that would be a lot slower. But either of those is a lot slower than using `mod` or `rem`.
sepp2k
+6  A: 

ifan I'm sure you know that in real life you would use mod or rem for this simple example, but the algorithm you are asking about is interesting. Here's a fun way to do it that emphasizes the functional nature of Haskell:

digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)

divisible11 = (== 0) . head . dropWhile (>= 11) . iterate (reduce11 . digits)
  where
    reduce11 []     = 0
    reduce11 (d:ds) = foldl combine d $ zip (cycle [(-), (+)]) ds
    combine d (op, d') = d `op` d'
Yitz
that was exactly what i was looking for. thank you very much for your helps
marco
A: 

How about...

mod11 n | n < 0 = 11 - mod11 (-n) 
        | n < 11 = n
        | otherwise = mod11 $ (n `mod` 10) - (n `div` 10) 
Landei
+1  A: 

Surely, div and mod are faster, but why not? I assume the problem is converting a number to a list of digits:

toDigits = map (read . (:[])) . show

56518 is converted to a String "56518", and each symbol in the string (every digit) is converted to a string itself with map (:[]), at this point we have ["5","6","5","1","8"], and we read every single-digit string as an integer value: [5,6,5,1,8]. Done.

Now we can calculate the sum of digits this way:

sumDigits x = sum (zipWith (*) (cycle [1,-1]) (reverse (toDigits x)))

cycle [1,-1] makes an infinite list [1, -1, 1, -1, ...], which we pair with the reversed list of digits (toDigit x), and multiply elements of every pair. So we have [8, -1, 5, -6, 5] and its sum.

Now we can do it recursively:

isDivisible x
  | x == 11 || x == 0 = True
  | x < 11            = False
  | x > 11            = isDivisible (sumDigits x)
jetxee