0

I'm looking for a non-recursive implementation of sum of digits (a "cross sum") of a non-negative number like this:

cs :: Int -> Int 
cs n = sum digits_of_n where digits_of_n = [ . | ... ] 

A cross sum of a number (e.g. 512) is the sum of its individual digits (e.g. 5 + 1 + 2 = 8)

cs takes a non-negative number "n" as input, then should use list comprehension to split the number to its digits (e.g. 1234 -> [1,2,3,4]), which then gets summed up.

The part where list comprehension is used is the question, I don't know how to implement that.

The "usual", recursive way would be extracting the digits from a number recursively using modulo and division, and then summing them up like this:

cs :: Int -> Int
cs n = if n == 0 then 0 else n `mod` 10 + cs (n `div` 10)

I have however difficulty expressing this without recursion and with list comprehension, does anyone have ideas regarding this?

  • Maybe you could try something like `map (read . pure) . show` to convert the number to string and then convert the single digits back to numbers. I might prefer the recursive solution, though. – chi May 24 '21 at 17:15

3 Answers3

1

First let me remark that such digit sums are an almost completely useless thing to compute, and there are way too many questions here about them.

...anyway – your question boils down to writing a function Int -> [Int] that produces the list of digits of a nonnegative number. Well, that can of course be done recursively, it can be done using show (which is a bit of a hack, but then, anything that requires the decimal digits will be a hack), with an unfold, or indeed with a list comprehension. In this case, you can't very well terminate on having consumed all digits anymore, but you can still compute the number of digits first, then determine each i-th digit separately:

decimalDigits :: Int -> [Int]
decimalDigits n = [ _ | i <- [0 .. ceiling . logBase 10 $ fromIntegral n ]

Then, to compute the i-th digit, you'll need to use mod and div much as you would in the recursive solution, just not with 10 but its i-th power.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
0

Here's one possible way:

f x = [(x `mod` (10 ^ y)) `div` (10 ^ (y-1)) | y <- [1.. ceiling $ logBase 10 $ fromIntegral x]]

This assumes that the number is input as an integer. It first calculates the closest integer greater than the base 10 logarithm of the input. This value provides a boundary for the next step, where we split up the number into digits using a combination of div and mod. Putting everything together, we end up with the digits from right to left.

shree.pat18
  • 21,449
  • 3
  • 43
  • 63
0

another indirect one

sumdigits = sum . map digitToInt . show

you need to import Data.Char(digitToInt)

karakfa
  • 66,216
  • 7
  • 41
  • 56