My goal is to write a function that calculates the maximum Collatz number below a certain number 'n'. (It's a Project Euler question for those who are familiar.)
Some context: A Collatz number for a given integer is equal to the length of the Collatz sequence for that integer. A Collatz sequence for an integer is calculated as follows: the first number ("n0") in the sequence is that integer itself; if n0 is even, the next number in the sequence ("n1") is equal to n / 2; if n0 is odd, then n1 is equal to 3 * n0 + 1. We continue recursively extending the sequence until we arrive at 1, at which point the sequence is finished. For example, the collatz sequence for 5 is: {5, 16, 8, 4, 2, 1} (because 16 = 3 * 5 + 1, 8 = 16 / 2, 4 = 8 / 2,...)
I'm trying to write a function ("maxCollatzUnder") which, when passed an integer "m", returns the integer (less than or equal to m) which has the longest Collatz sequence (i.e., largest Collatz number). For example, maxCollatz 20 (i.e., what integer below (inclusive) 20 has the longest collage sequence?) should return 19 (the number 19 has a Collatz sequence of length 21: [19,58,29,88,44,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]).
In the code below, the "collatz" and "collatzHelper" functions compile and run correctly. I'm having trouble with the "maxCollatzUnder" function. This function intends to (I) create a list of 2-tuples (x,y) for each integer x ranging from 1 to m (where m is the function argument) and where where y represents the Collatz number for integer x and then (II) look through the list for the highest Collatz number (i.e., y) and return its associated integer (i.e., x)
maxCollatzUnder n = foldl(\acc (i,j) -> if j > acc then i else acc) 0
(zip [1..n] ( map collatzLength [1..n]))
where collatzLength n = length . collatz $ n
collatz n = map truncate $ collatzHelper n
collatzHelper 0 = [0]
collatzHelper 1 = [1]
collatzHelper n
| (truncate n) `mod` 2 == 0 = [n] ++ collatzHelper (n/2)
| otherwise = [n] ++ collatzHelper (3*n+1)
I get the following error when I (attempt to) compile.
*Main> :l PE14Collatz.hs
[1 of 1] Compiling Main ( PE14Collatz.hs, interpreted )
PE14Collatz.hs:7:89:
No instance for (RealFrac Int)
arising from a use of `collatzLength'
In the first argument of `map', namely `collatzLength'
In the second argument of `zip', namely
`(map collatzLength [1 .. n])'
In the third argument of `foldl', namely
`(zip [1 .. n] (map collatzLength [1 .. n]))'
Failed, modules loaded: none.
What's curious is that the code compiles and runs correctly if I change the "maxCollatzUnder" to the following code (see below). The only change is that, in the version below, the fold function returns "j" (i.e., the largest Collatz number) instead of "i" (i.e., the integer which generates the largest Collatz number).
maxCollatzUnder n = foldl(\acc (i,j) -> if j > acc then j else acc) 0
(zip [1..n] ( map collatzLength [1..n]))
where collatzLength n = length . collatz $ n
Suggestions on a more efficient/elegant approach are welcome though I would still be interested in understanding the cause of this error.