re: Write a script to find "Happy Numbers" VIEW POST

re: Adding a solution in Haskell: -- core function; read from bottom to top f :: Int -> Int f = sum -- Sum up the squares . map ((^2)...

Here is my solution, to keep me fresh in haskell (I rarely have the possibility to use it in projects and thus never learned it properly):

-- Square summation
squareSum :: [Integer] -> Integer
squareSum = sum . map (^2)

-- Splitting n into its digits
splitNum :: Integer -> [Integer]
splitNum n
  | n < 10 = [n]
  | otherwise = (splitNum $ quot n 10) ++ [n `mod` 10]

-- Check for happiness
isHappy :: Integer -> Bool
isHappy 1 = True
isHappy 4 = False -- 4 is in every unhappy cycle
isHappy n = (isHappy . squareSum . splitNum) n

main = print $ filter isHappy [1..200]

I'm glad to see some Haskell here. :) I somehow prefer your computational approach to split the number over my quick string hack. You can easily change the base.

I have done a lot of parsing stuff in Haskell with parsec, attoparsec and readP, lately. So I instantly think of parsing when I see the problem of splitting a number into digits. The detour via strings is comfortable, because it uses the read parser. but

"Challenge" accepted to solve it computationally. :)

To import as few / basic libraries as reasonably achievable, I decided not to use the parsec library but to write a homemade digit parser.

What you do in splitNum reminds me of the quotRem function (that I found when I coded for the Challenge about Kaprekar numbers, here). quotRem just needs a swap to make for a nice digit parser in a very organic way: When dividing by 10 the integer quotient is the state of the state monad (that's still to parse) and the remainder is a parsed digit.

import Control.Monad.State
import Control.Monad.Loops(untilM)

swap :: (a,b) -> (b,a)
swap (x,y) = (y,x)

-- digit parser
digit :: Integral a => State a a
digit = state $ \s -> swap $ quotRem s 10

-- eof condition
eof :: Integral a => State a Bool
eof = get >>= \s -> return $ s == 0

-- parsing the digits of a number into a (reversed) list of digits
digits :: Integral a => a -> [a]
digits = evalState (digit `untilM` eof)

-- core function
f = sum . map (^2) . digits

-- iteration of f by recursion of isHappy 
isHappy n | n == 4 = False
          | n == 1 = True
          | otherwise = isHappy (f n)

I am a bit biased to use (faster) Ints in my prototypes, and use Integers where really needed, but I adopt your approach with Integers by at least generalizing the code to Integral types.

Although I learned to prefer folds over homemade recursion, I'm afraid the abstractness of foldP is a little bit hard to read, so perhaps I stick with the homemade recursion, this time. :)

Code of Conduct Report abuse