首先,在這樣的問題中包含必要的定義。
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的角色。 –