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)