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

-- core function; read from bottom to top

f :: Int -> Int
f = sum          -- Sum up the squares
. map ((^2)    -- Compute squares
.read   -- Convert digit strings to Ints
.(:[])) -- Explode number string to list of digit strings
. show         -- Convert input number to string

-- This is a folding pattern with a tricky break condition,
-- depending on the list element and the accumulator.

foldP :: (a -> b -> b) -> (a -> b -> Bool) -> b -> [a] -> b
foldP f p acc [] = acc
foldP f p acc (x:xs) | p x acc = acc
| otherwise = foldP f p (f x acc) xs

-- Cut off a list's tail, once a number is repeating.
-- (reverts the preserved part of the list)

cut :: Eq a => [a] -> [a]
cut = foldP (:) elem [] -- fold by appending and checking if x is already in list

-- Iterate the core function, cut the result list and check if the final
-- result is 1.

isHappy :: Int -> Bool
isHappy = (== 1) . head . cut . iterate f

main = print $filter isHappy [1..200]  Note that Haskell function composition with the (.) operator is read from right to left (or from bottom to top, respectively). The hardest part for FP is folding with a non-trivial break condition, here. 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. :)

And now that I have learned a simpler break condition for the problem, it is easier:

f :: Int -> Int
f = sum          -- Sum up the squares
. map ((^2)    -- Compute squares
.read   -- Convert digits to Ints
.(:[])) -- Explode number string to list of digit strings
. show         -- Convert input number to string

isHappy :: Int -> Bool
isHappy n | n == 4 = False
| n == 1 = True
| otherwise = isHappy (f n)

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


On the other hand, I like the possibility of my original code to see the list of intermediate results to get a feeling for the problem.

code of conduct - report abuse  