Haskell初学者:“没有......因...而产生的错误”错误

Haskell初学者:“没有......因...而产生的错误”错误

问题描述:

我的目标是编写一个函数来计算低于特定数字'n'的最大Collat​​z数。 (对于那些熟悉的人来说,这是个项目欧拉问题。)Haskell初学者:“没有......因...而产生的错误”错误

某些上下文:给定整数的Collat​​z数等于该整数的Collat​​z序列的长度。一个整数的Collat​​z序列计算如下:序列中的第一个数字(“n0”)是该整数本身;如果n0是偶数,序列中的下一个数字(“n1”)等于n/2;如果n0是奇数,那么n1等于3 * n0 + 1。我们继续递归地扩展序列直到我们到达1,此时序列结束。例如,5的collat​​z序列是:{5,16,8,4,2,1}(因为16 = 3 * 5 + 1,8 = 16/2,4 = 8/2,...)

我想写一个函数(“maxCollat​​zUnder”),当它传递一个整数“m”时,返回具有最长Collat​​z序列(即最大Collat​​z数)的整数(小于或等于m) 。例如,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])。

在下面的代码中,“collat​​z”和“collat​​zHelper”函数编译并正确运行。我在使用“maxCollat​​zUnder”功能时遇到了问题。该函数旨在(1)为1到m范围内的每个整数x(其中m是函数参数)创建一个2元组(x,y)的列表,其中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. 

有什么奇怪的是,代码编译,如果我改变“maxCollat​​zUnder”下面的代码(见下文)运行正常。唯一的变化是,在下面的版本中,折叠函数返回“j”(即,最大Collat​​z数)而不是“i”(即,产生最大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 

对更高效/优雅的方法的建议是受欢迎的,尽管我仍然有兴趣了解这个错误的原因。

+0

你认为这些函数的类型是什么?例如,“collat​​z”的类型应该是什么? – bheklilr 2014-10-02 02:16:52

因为你使用的truncate(的RealFrac的方法)和/(的Fractional的方法中,RealFrac超类)的,哈斯克尔推断出以下两种类型签名的最后两个功能:

collatz :: (RealFrac a, Integral b) => a -> [b] 
collatzHelper :: RealFrac a => a -> [a] 

哈斯克尔然后尝试推算的maxCollatzUnder类型,其思维过程是这样的:

  • “在collatzLength n = length . collatz $ n ,我们通过ncollatz,所以collatzLength的参数必须是RealFrac。“

  • “因此,在map collatzLength [1..n][1..n]必须是RealFrac值的列表。“

  • ”因此,在map collatzLength [1..n]n必须是RealFrac类型。“

  • ”。因此,在zip [1..n]n(其是相同n)必须是RealFrac式等[1..n]是一个的RealFrac名单。”

  • “因此,在(\acc (i,j) -> if j > acc then i else acc)i必须是RealFrac。”

  • “由于上述的λ可以返回iacc,它们必须是相同的类型”

  • “因为j正在相比accj必须是相同的类型acc - 并且因此相同类型iRealFrac。“

  • ”但WAIT - jcollatzLength的返回值,这是length一个调用的返回值,因此它必须是一个IntInt不在RealFrac

  • ”错误!错误!”

我现在得走了(编译惊天动地不喜欢我放弃自己的秘密),但最短的解决方法是不使用truncate/,只是使用div的(地板),整数

+0

非常感谢您花时间解释!您的解释非常有意义(并且使用“股利“,而不是”截断“和”/“的组合,确实工作!)。我会投票,但我没有 – iceman 2014-10-02 03:31:32

+0

必要的帖子数量.... – iceman 2014-10-02 03:31:59