Haskell初学者:“没有......来自...的错误。”错误

时间:2014-10-02 01:58:50

标签: haskell collatz

我的目标是编写一个函数来计算低于某个数字' n'的最大Collat​​z数。 (对于那些熟悉的人来说,这是一个项目欧拉问题。)

某些上下文:给定整数的Collat​​z数等于该整数的Collat​​z序列的长度。整数的Collat​​z序列计算如下:序列中的第一个数字(&#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; maxCollat​​zUnder&#34;),当传递一个整数&#34; m&#34;时,返回整数(小于或等于m),具有最长的Collat​​z序列(即最大的Collat​​z数)。例如,maxCollat​​z 20(即,低于(包括)20的整数具有最长的拼贴序列?)应该返回19(数字19具有长度为21的Collat​​z序列:[19,58,29,88,44,22, 11,34,17,52,26,13,40,20,10,5,16,8,4,2,1])。

在下面的代码中,&#34; collat​​z&#34;和&#34; collat​​zHelper&#34;函数编译并正确运行。我在使用&#34; maxCollat​​zUnder&#34;功能。该函数旨在(I)为每个整数x创建一个2元组(x,y)的列表,范围从1到m(其中m是函数参数),其中y表示整数x的Collat​​z数,然后( II)查看列表中最高的Collat​​z数(即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; maxCollat​​zUnder&#34;那么代码会编译并正确运行。到以下代码(见下文)。唯一的变化是,在下面的版本中,折叠函数返回&#34; j&#34; (即最大的Collat​​z号码)而不是&#34; i&#34; (即产生最大Collat​​z数的整数)。

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

欢迎提出有关更有效/更优雅方法的建议,但我仍然有兴趣了解此错误的原因。

1 个答案:

答案 0 :(得分:6)

由于您使用truncateRealFrac的方法)和/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中的nzip [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;由于iacc进行了比较,j必须与acc的类型相同 - 因此类型与j相同{1}}和acc。&#34;

  • &#34;但是等待i是来自RealFrac的返回值,这是对j的调用的返回值,因此它必须是一个collatzLengthlength不在Int&#34;

  • &#34; ERROR! !ERROR&#34;

我现在必须去(编译器Cabal并不喜欢我泄露他们的秘密),但最短的修复是不使用IntRealFrac而只使用{{1 for(floored)整数除法。