我的目标是编写一个函数来计算低于某个数字' n'的最大Collatz数。 (对于那些熟悉的人来说,这是一个项目欧拉问题。)
某些上下文:给定整数的Collatz数等于该整数的Collatz序列的长度。整数的Collatz序列计算如下:序列中的第一个数字(&#34; n0&#34;)是整数本身;如果n0是偶数,则序列中的下一个数字(&#34; n1&#34;)等于n / 2;如果n0是奇数,那么n1等于3 * n0 + 1.我们继续递归地扩展序列,直到我们到达1,此时序列结束。例如,5的折叠序列是:{5,16,8,4,2,1}(因为16 = 3 * 5 + 1,8 = 16 / 2,4 = 8/2,......)< / p>
我试图编写一个函数(&#34; maxCollatzUnder&#34;),当传递一个整数&#34; m&#34;时,返回整数(小于或等于m),具有最长的Collatz序列(即最大的Collatz数)。例如,maxCollatz 20(即,低于(包括)20的整数具有最长的拼贴序列?)应该返回19(数字19具有长度为21的Collatz序列:[19,58,29,88,44,22, 11,34,17,52,26,13,40,20,10,5,16,8,4,2,1])。
在下面的代码中,&#34; collatz&#34;和&#34; collatzHelper&#34;函数编译并正确运行。我在使用&#34; maxCollatzUnder&#34;功能。该函数旨在(I)为每个整数x创建一个2元组(x,y)的列表,范围从1到m(其中m是函数参数),其中y表示整数x的Collatz数,然后( II)查看列表中最高的Collatz数(即y)并返回其相关的整数(即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)
当我(尝试)编译时,我收到以下错误。
*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.
奇怪的是,如果我更改了&#34; maxCollatzUnder&#34;那么代码会编译并正确运行。到以下代码(见下文)。唯一的变化是,在下面的版本中,折叠函数返回&#34; j&#34; (即最大的Collatz号码)而不是&#34; i&#34; (即产生最大Collatz数的整数)。
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
欢迎提出有关更有效/更优雅方法的建议,但我仍然有兴趣了解此错误的原因。
答案 0 :(得分:6)
由于您使用truncate
(RealFrac
的方法)和/
(Fractional
的方法,RealFrac
的超类),Haskell为您的最后两个函数推断以下两种类型的签名:
collatz :: (RealFrac a, Integral b) => a -> [b]
collatzHelper :: RealFrac a => a -> [a]
然后,Haskell试图推断maxCollatzUnder
的类型,其思维过程如下:
&#34;在collatzLength n = length . collatz $ n
中,我们将n
传递给collatz
,因此collatzLength
的参数必须为{{1} }}&#34;
&#34;因此,在RealFrac
中,map collatzLength [1..n]
必须是[1..n]
值的列表。&#34;
&#34;因此,RealFrac
中的n
必须是map collatzLength [1..n]
类型。&#34;
&#34;因此,RealFrac
中的n
(zip [1..n]
}必须是n
类型,因此{{1} }是RealFrac
s。&#34;
&#34;因此,[1..n]
中的RealFrac
必须是i
。&#34;
&#34;因为上述lambda可以返回(\acc (i,j) -> if j > acc then i else acc)
或RealFrac
,所以它们必须是同一类型。&#34;
&#34;由于i
与acc
进行了比较,j
必须与acc
的类型相同 - 因此类型与j
相同{1}}和acc
。&#34;
&#34;但是等待i
是来自RealFrac
的返回值,这是对j
的调用的返回值,因此它必须是一个collatzLength
,但length
不在Int
!&#34;
&#34; ERROR! !ERROR&#34;
我现在必须去(编译器Cabal并不喜欢我泄露他们的秘密),但最短的修复是不使用Int
和RealFrac
而只使用{{1 for(floored)整数除法。