首先,在这样的问题中包含必要的定义。
hyp :: Floating a => a -> a -> a
hyp a b = sqrt $ a^2 + b^2
现在。 您可以在列表解析中“嵌入”功能。显然你只是选择了一些不幸的! round
有以下类型:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> :t round
round :: (Integral b, RealFrac a) => a -> b
所以,round c == c
是有道理的,你需要有一些类型的两个Integral
实例的RealFrac
和。换句话说,这种类型将包含分数,但其所有元素将是整数†。那么,你不能拥有你的蛋糕,也不能吃它!
如果你真的写出了一些类型的签名,这个问题会更加明显,就像在Haskell中经常出现的那样。虽然这样玩弄,但通常只需选择一些简单的示例类型即可。也许最合理的事情似乎:
Prelude> [ c | a <- [1..3], b <- [1..4], let c = hyp a b, c == round c] :: [Integer]
<interactive>:6:41:
No instance for (Floating Integer) arising from a use of ‘hyp’
In the expression: hyp a b
In an equation for ‘c’: c = hyp a b
In the expression:
[c |
a <- [1 .. 3], b <- [1 .. 4], let c = hyp a b, c == round c] ::
[Integer]
好了,Integer
不hyp
工作,因为你正在尝试做真正的算法,这些平方根。这不可能与Integer
,您需要Floating
类型如Double
。让我们试试:
Prelude> [ c | a <- [1..3], b <- [1..4], let c = hyp a b, c == round c] :: [Double]
<interactive>:8:55:
No instance for (Integral Double) arising from a use of ‘round’
In the second argument of ‘(==)’, namely ‘round c’
In the expression: c == round c
In a stmt of a list comprehension: c == round c
好吧,这是因为正如我所说,round
总是给人整体式的结果。但是,你总是可以这样的整体式再转换为Double
:
Prelude> [ c | a <- [1..3], b <- [1..4], let c = hyp a b, c == fromIntegral (round c)] :: [Double]
[5.0]
请注意,这是不是真的,虽然一个很好的解决方案:你真的不想要的结果进行浮点如果你去检查已经这些元素真的是完整的!在这种情况下,我建议不要仅仅评估hyp
。更好地运用这个理解:此版本
Prelude> [ c | a <- [1..3], b <- [1..4], let c² = a^2 + b^2; c = round . sqrt $ fromIntegral c², c^2==c²] :: [Integer]
[5]
的一个大论据是,它在Integer
的比较,而不是在Double
。如果你能够提供帮助的话,浮点平等比较是你应该完全避开的东西;在这种情况下,它是主要是无害,因为有趣的是整数子集,它实际上可以完全表示(不像小数部分,如0.1
)。您仍然可以通过这种方式得到错误的结果:特别是对于足够大的浮点数,c == fromInteger (round c)
将总是为真,因为超过一定的阈值,所有的值都是积分。
Prelude> [ c | a <- take 4 [1000000000000..], b <- take 5 [1000000000000..], let c = hyp a b, c == fromIntegral (round c)] :: [Float]
[1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12,1.4142135e12]
但这些都不是真正正确的积分hypothenuses,因为你可以用做在Integer
比较的版本中看到:
Prelude> [ c | a <- take 4 [1000000000000..], b <- take 5 [1000000000000..], let c² = a^2 + b^2; c = round . sqrt $ fromIntegral c², c^2==c²] :: [Integer]
[]
严格地说,这种改进版本也并不安全,但 - 它不会给出误报,但可能找不到实际的毕达哥拉斯三元组,因为有损浮点步骤已经可能破坏平等。要做到这一点真正正确的,你需要的所有积分
intSqrt :: Integral a => a -> Maybe a
这可以通过采取浮动sqrt
作为在整数运算几个回合伪Newton-Raphson的初始值可能做得相当有效。
†原则上,round
功能还可以有更宽松的签名。
round' :: (Num b, RealFrac a) => a -> b
round' = fromInteger . round
与该版本,原来的代码会工作。
我不知道你的'hyp'是什么样的,但是你可以在理解的最后一个语句 –
上试试'c == fromIntegral(round c)'这就是它,非常感谢!在继续前进之前,我只需要研究fromIntegral的角色。 –