任务是找到所有可以表示为两个自然数的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)
我该如何解决这个问题?
答案 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]]
这将是我的最终版本。
此外,尽管上述定义没有通过搜索完美正方形的范围来参数化,但是当作为参数时,可以应用所有提出的重构;我把这作为一个很好的练习让读者检查他们是否了解每一个变化。