未解决的顶级重载

时间:2017-10-23 17:53:46

标签: haskell

任务是找到所有可以表示为两个自然数的sqrt之和的二值数。 我试试这个:

func = [sqrt (x) + sqrt (y) | x <- [10..99], y <- [10..99], sqrt (x) `mod` 1 == 0, sqrt (y) `mod` 1 == 0]

结果:

  

未解决的顶级重载绑定:func   突出的背景:(积分b,浮动b)

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:5)

这是因为这两种类型之间存在冲突:

sqrt :: Floating a => a -> a
mod :: Integral a => a -> a -> a

因为您编写mod (sqrt x) 1,并且sqrt被约束为返回相同类型,编译器将尝试查找同时满足{x的{​​{1}}类型。 1}} Floating的约束和sqrt的{​​{1}}约束。 Integral库中没有满足这两种约束的类型。

快速解决方法是使用mod' :: Real a => a -> a -> a

mod

但是,从您发布的错误来看,您可能没有使用GHC,base可能是GHC主义。在这种情况下,您可以从here复制定义(以及辅助函数import Data.Fixed func = [sqrt (x) + sqrt (y) | x <- [10..99], y <- [10..99], sqrt (x) `mod'` 1 == 0, sqrt (y) `mod'` 1 == 0] 的定义)。

但我建议更多参与修复。关键的观察是,如果mod',那么div',那么我们就可以避免调用x = sqrt y。我们可以迭代平方根,而不是迭代数字并检查它们是否具有干净x*x = y。他们的方块肯定会有干净的方根。这种重构的直接应用可能如下所示:

sqrt

当然,sqrt是一个可怕的名字(它甚至不是一个函数!),而sqrts = takeWhile (\n -> n*n <= 99) . dropWhile (\n -> n*n < 10) $ [0..] func = [x + y | x <- sqrts, y <- sqrts] 是我们自己可以计算的常量,而且很短,我们应该只是内联它。所以我们可以简化为:

func

此时,我想知道我是否真的想写这个,更喜欢

sqrts

,与前一次迭代不同,它没有任何重复。它失去了为什么这是一个有趣的常数的所有解释力,所以你肯定想要一个评论。

numberSums = [x + y | x <- [4..9], y <- [4..9]]

这将是我的最终版本。

此外,尽管上述定义没有通过搜索完美正方形的范围来参数化,但是当作为参数时,可以应用所有提出的重构;我把这作为一个很好的练习让读者检查他们是否了解每一个变化。