1

Today, I am playing with Collatz sequences in Haskell ...

Here is my code:

collatzLength :: Int -> Integer -> Int
collatzLength count 1 = count
collatzLength count n = collatzLength (count+1) $ if n `mod` 2 == 0 then n `div` 2 else 3*n+1

main =
    print (collatzLength 1 (10^10000 + 1))

What I would like to do is to iterate infinitely on [1, 3 ..]. Each time a new maximum Collatz length is found, I want to display it on screen, and continue. I have no idea on how to do that in Haskell, as I have to keep and update the maximum length value somewhere.

melpomene
  • 84,125
  • 8
  • 85
  • 148
ols
  • 173
  • 7

1 Answers1

2

Use map and an infinite range

main = print $ map (collatzLength 1) [1,3..]

or use explicit recursion

main :: IO ()
main = loop 1

loop :: Int -> IO ()
loop n = do
   print (collatzLength 1 n)
   loop (n+2)

The latter approach lets you have a finer control on the loop.

Note that every loop computes the sequence number from scratch, without exploiting previously computed results. For a more efficient approach, look up memoization (not to be confused with "memorization"). Such techniques allow the program to "remember" the result of previously computed recursive calls, so that new calls do not have to recompute the same value.

If you want to keep the maximum of all returned values, you can use

loop :: Int -> Int -> IO ()
loop n prevMax = do
   let m = collatzLength 1 n
   putStrLn $ "collatzLength 1 " ++ show n ++ " = " ++ show m
   let nextMax = max prevMax m
   putStrLn $ "current maximum = " ++ show nextMax
   loop (n+2) nextMax

But I do not want to print all the results. Only the lengths that are higher than the "current" maximum length.

Then, generate a list of those "higher" points:

-- Assumes a list of positive numbers.
-- Returns the list of those elements which are larger than all the
-- previous ones.
highPoints :: [Int] -> [Int]
highPoints xs = go 0 xs
   where
   go :: Int -> [Int] -> [Int]
   go _          []     = []
   go currentMax (n:ns) | n > currentMax = n : go n ns
                        | otherwise      = go currentMax ns

main :: IO ()
main = do 
   let collatzSequence :: [Int]
       collatzSequence = map (collatzLength 1) [1,3..]
   print (highPoints collatzSequence)
chi
  • 111,837
  • 3
  • 133
  • 218
  • That doesn't compute a running maximum. – melpomene May 20 '17 at 08:03
  • @melpomene I added the running maximum, but I'm unsure about what the OP actually needs. Their wording is a bit unclear to me at the end. – chi May 20 '17 at 08:09
  • 1
    Thanks. But I do not want to print all the results. Only the lengths that are higher than the "current" maximum length. – ols May 20 '17 at 08:09
  • The type signature for `loop` that keeps track of the running maximum looks wrong. You are missing the `prevMax` argument type. Also `nextMax` is misspelt on the last line of that function. – basile-henry May 20 '17 at 12:54
  • 1
    @basile-henry Thanks, should be fixed now. – chi May 20 '17 at 13:55