本文介绍了使用Haskell范围:为什么要在一个范围内映射一个浮点函数使它返回一个额外的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,由于不精确的性质,漂浮物会导致范围内奇怪的行为。
我会期望值不精确的可能性。例如:
[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]

这很奇怪,但在这里解释。我可以这样做,我想:

  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的>在列表列表(map(* 1.0)列表)中设置list = [1,3..10] 
[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]


这不仅仅是映射:

$ p $ ghci中>最后[1,3..10]
9

ghci> 1.0 *(last [1,3..10])
11.0

一个范围的结果函数可以影响该范围的实际评估结果?

解决方案

当你看到一个浮点函数被映射到一个列表上(或在列表的一个元素上使用,就像在我的列表中一样)例如使用最后一个),它将推断该列表的类型是浮点,因此评估范围,如果它是 [1,3..10] :: [Float] 而不是我想要的,它是 [1,3..10] :: [Int]



此时,它使用Float规则进行枚举,正如我链接的。



预期的行为可以像这样强制:

pre > ghci的> map(\ x - >(fromIntegral x)/ 10)([1,3..10] :: [Int])
[0.1,0.3,0.5,0.7,0.9]

依靠Haskell的类型推断,我们可以删除 :: [Int]

  ghci> :从(x)/ 10)
::(小数a,积分a1)=>(从整数x)/ 10) a1 - > a


I know that floats can lead to odd behavior in ranges due to their imprecise nature.I would expect the possibility of imprecise values. For instance:[0.1,0.3..1] might give [0.1,0.3,0.5,0.7,0.8999999999999999] instead of [0.1,0.3,0.5,0.7,0.9]

In addition to the precision loss, however, I get an extra element:

ghci> [0.1,0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]

This is weird, but explained here. I could work around it like this, I suppose:

ghci> [0.1,0.3..0.99]
[0.1,0.3,0.5,0.7,0.8999999999999999]

But that's kind of gross. Maybe there's a cleaner way. For this simple example, of course, I could just use the range [0.1,0.3..0.9] and everything is fine.

But in a more complex example, I may not quickly know (or care to figure out, if I'm lazy) the exact upper bound I should use. So, I'll just make a range of integers and then divide by 10, right? Nope:

ghci> map (/10) [1,3..10]
[0.1,0.3,0.5,0.7,0.9,1.1]

Any floating point function seems to cause this behavior:

ghci> map (*1.0) [1,3..10]
[1.0,3.0,5.0,7.0,9.0,11.0]

Whereas a non-floating function doesn't:

ghci> map (*1) [1,3..10]
[1,3,5,7,9]

While it seems unlikely, I thought that maybe some lazy evaluation was at play, and tried to force evaluation of the range first:

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]

Obviously, using the literal list instead of the range works fine:

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]

It isn't just mapping either:

ghci> last [1,3..10]
9

ghci> 1.0 * (last [1,3..10])
11.0

How does applying a function to the result of a range can impact the actual evaluated result of that range?

解决方案

I answered this for myself as I was writing it.

Haskell uses type inference, so when it sees a floating point function being mapped over a list (or used on an element of that list, as in my example using last), it is going to infer the type of that list to be floating point and therefore evaluate the range as if it were [1,3..10] :: [Float] instead of what I was intending, which is [1,3..10] :: [Int]

At this point, it uses the Float rules for enumerating, as described in the post that I linked to in the question.

The expected behavior can be forced like this:

ghci> map (\x -> (fromIntegral x) / 10) ([1,3..10]::[Int])
[0.1,0.3,0.5,0.7,0.9]

Relying on Haskell's type inference, we can drop the ::[Int] since fromIntegral causes our lambda expression to have the correct type:

ghci> :t (\x -> (fromIntegral x) / 10)
(\x -> (fromIntegral x) / 10)
  :: (Fractional a, Integral a1) => a1 -> a

这篇关于使用Haskell范围:为什么要在一个范围内映射一个浮点函数使它返回一个额外的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-26 04:28