Haskell素数生成器错误

时间:2013-11-02 01:08:17

标签: haskell compiler-errors primes

我试过了:

composites=[c|c<-[4..], any (\p->(c`mod`p == 0)) (takeWhile (< (sqrt c)) primes)]
primes=2:[p|p<-[3..], not p `elem` (takeWhile (<p) composites)]

得到了:

pad.hs:1:19:
    No instance for (Num Bool) arising from the literal `4'
    Possible fix: add an instance declaration for (Num Bool)
    In the expression: 4
    In the expression: [4 .. ]
    In a stmt of a list comprehension: c <- [4 .. ]

pad.hs:1:30:
    No instance for (Integral Bool) arising from a use of `divisible'
    Possible fix: add an instance declaration for (Integral Bool)
    In the first argument of `any', namely `(divisible c)'
    In the expression: any (divisible c) (factors c)
    In a stmt of a list comprehension: any (divisible c) (factors c)

pad.hs:3:43:
    No instance for (Floating Bool) arising from a use of `sqrt'
    Possible fix: add an instance declaration for (Floating Bool)
    In the second argument of `(<)', namely `sqrt c'
    In the first argument of `takeWhile', namely `(< sqrt c)'
    In the expression: takeWhile (< sqrt c) primes
Failed, modules loaded: none.

我认为它处理的是什么类型的数字很困惑,但我不确定。有什么提示吗?

2 个答案:

答案 0 :(得分:2)

  

我认为它与处理的数字类型相混淆

非常正确!那么你为什么不告诉它呢?在实际实现之前,在Haskell中编写函数签名总是一个好主意。当出现问题时,这不仅可以防止这些令人困惑的编译器消息,而且在实际设计函数时它也是一个非常好的指南。

所以在你的情况下,你可能想要 1

composites, primes :: [Integer]

当然不能解决问题,但它会使错误信息更加清晰:

  

前奏&GT;让复合材料,素数:: [整数]; composites = [c | c&lt; - [4 ..],any(\ p - &gt; c`mod`p == 0)(takeWhile(&lt; sqrt c)primes)]; primes = 2:[p | p&lt; - [3 ..],而不是p`elem`(takeWhile(&lt; p)composites)]   

&LT;互动&GT;:2:128:
  无法将预期类型“Integer”与实际类型“Bool”匹配   在表达式中:p
  在`(:)'的第二个参数中,即
  `[p | p&lt; - [3 ..],而不是p`elem`(takeWhile(&lt; p)复合材料)]'
  在表达式中:
  2:[p | p&lt; - [3 ..],而不是p`elem`(takeWhile(&lt; p)复合材料)]   
  &LT;互动&GT;:2:169:
  无法将类型“Integer”与“Bool”匹配   预期类型:[Bool]
  实际类型:[整数]
  在“takeWhile”的第二个论点中,即`composites'   在“elem”的第二个参数中,即
  `(takeWhile(&lt; p)复合材料)'
  在表达式中:not p`elem`(takeWhile(&lt; p)composites)

它仍然不完全正确,但至少它现在将错误本地化到它的位置:在primes中,p被推断为Bool,这当然是错误。 bool的原因是你有not p `elem` (...)。显然你认为这被解析为not (p`elem`(...)),但事实并非如此:普通前缀函数应用程序具有比任何中缀运算符更高的优先级。重要的是要知道(这也是为什么你不需要sqrt c(< sqrt c)周围的parens。

让我们解决这个问题,然后还有一个问题:

  

前奏&GT;让复合材料,素数:: [整数]; composites = [c | c&lt; - [4 ..],any(\ p-&gt;(c`mod`p == 0))(takeWhile(&lt;(sqrt c))primes)]; primes = 2:[p | p&lt; - [3 ..],而不是$ p`elem`(takeWhile(&lt; p)composites)]

  
  &LT;互动&GT;:3:99:
  没有因使用“sqrt”而产生的(浮动整数)实例   可能的解决方法:为(Floating Integer)添加实例声明
  在`(&lt;)'的第二个参数中,即`(sqrt c)'   在`takeWhile'的第一个参数中,即`(&lt;(sqrt c))'   在“任何”的第二个论点中,即
  `(takeWhile(&lt;(sqrt c))primes)'

现在已经发现:你正在处理整数,但是sqrt显然会产生一般无理数,所以只有Floating类型才有意义。为了解决这个问题,你可以使用(诚然丑陋,但确定)sqrt' = round . sqrt . fromIntegral


1 实际上,这种单态签名可能并不理想 - 出于各种原因(主要是效率),您可能更喜欢Int。为了安全起见,可以选择Integral a => [a];但是多态值不会在顶层“记忆”,这在这个例子中也是一个很大的问题。

答案 1 :(得分:1)

  

任何提示?

好了,现在你修好了,

composites=[c|c<-[4..], any ((==0).(c`mod`)) (takeWhile ((<= c).(^2)) primes)]
primes=2:[p|p<-[3..], not (p `elem` takeWhile (<= p) composites)]

考虑是否可以加快速度。首先,elem完全消耗第二个参数,当第一个参数不在其中时,始终从头开始搜索。但是,如果我们只是在合成中搜索 16 ,那么当我们搜索 17 时,就没有必要重新开始了 strong> next - 我们可以从同一点继续:

notAmong (_, (k:ks,c:cs))              -- a candidate that is not among
   | k == c    = (Nothing, (ks,cs))    --     the composites, is a prime
   | otherwise = (Just k, (ks,c:cs))   -- (k < c)
primes = 2 : [p | (Just p,_) <- iterate notAmong (Just 3, ([4..],composites))]

我们融合函数notelemtakewhile,速度很快。

尝试找出此版本的empirical orders of growth并与原始版本进行比较,这很有趣。