我知道漂浮物由于其不精确的性质而导致范围内的奇怪行为。
我预计价值不精确的可能性。例如:
[0.1,0.3..1]
可能会[0.1,0.3,0.5,0.7,0.8999999999999999]
代替[0.1,0.3,0.5,0.7,0.9]
然而,除了精度损失之外,我还有一个额外的元素:
ghci> [0.1,0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
这很奇怪,但解释here。我想这样可以解决这个问题,我想:
ghci> [0.1,0.3..0.99]
[0.1,0.3,0.5,0.7,0.8999999999999999]
但这有点糟糕。也许有一种更清洁的方式。对于这个简单的例子,当然,我可以使用范围[0.1,0.3..0.9]
,一切都很好。
但是在一个更复杂的例子中,我可能不会很快知道(或者想弄清楚,如果我是懒惰的)我应该使用的确切上限。所以,我只是制作一系列整数然后除以10,对吧?都能跟得上:
ghci> map (/10) [1,3..10]
[0.1,0.3,0.5,0.7,0.9,1.1]
任何浮点函数似乎都会导致此行为:
ghci> map (*1.0) [1,3..10]
[1.0,3.0,5.0,7.0,9.0,11.0]
非浮动函数不是:
ghci> map (*1) [1,3..10]
[1,3,5,7,9]
虽然看起来不太可能,但我认为可能有一些懒惰的评估在起作用,并试图首先强制评估范围:
ghci> let list = [1,3..10] in seq list (map (*1.0) list)
[1.0,3.0,5.0,7.0,9.0,11.0]
显然,使用文字列表而不是范围可以正常工作:
ghci> map (*1.0) [1,3,5,7,9]
[1.0,3.0,5.0,7.0,9.0]
ghci> let list = [1,3,5,7,9] in seq list (map (*1.0) list)
[1.0,3.0,5.0,7.0,9.0]
它不只是映射:
ghci> last [1,3..10]
9
ghci> 1.0 * (last [1,3..10])
11.0
如何将函数应用于范围的结果会影响该范围的实际评估结果?
答案 0 :(得分:11)
我在写这篇文章时为自己回答了这个问题。
Haskell使用类型推断,因此当它看到一个浮点函数被映射到一个列表上(或者在该列表的一个元素上使用时,就像在我的示例中使用last),它将推断该列表的类型为是浮点数因此评估范围,好像它是[1,3..10] :: [Float]
而不是我想要的,[1,3..10] :: [Int]
此时,它使用Float规则进行枚举,如post that I linked to in the question中所述。
可以像这样强制预期的行为:
ghci> map (\x -> (fromIntegral x) / 10) ([1,3..10]::[Int])
[0.1,0.3,0.5,0.7,0.9]
依赖于Haskell的类型推断,我们可以删除::[Int]
,因为fromIntegral导致我们的lambda表达式具有正确的类型:
ghci> :t (\x -> (fromIntegral x) / 10)
(\x -> (fromIntegral x) / 10)
:: (Fractional a, Integral a1) => a1 -> a