简体   繁体   English

Haskells背后的基本原理`succ`数字(浮点数)

[英]Rationale behind Haskells `succ` on numbers (floats)

I was a bit surprised to learn that Haskell defines its succ function on numbers as adding one: 我有点惊讶地发现Haskell将数字succ函数定义为添加一个:

succ :: a -> a
The successor of a value. 价值的继承者。 For numeric types, succ adds 1 . 对于数字类型,succ添加1

Although for integral values, this seems reasonable there are a few problems: 虽然对于整数值,这似乎是合理的,但有一些问题:

  • what if you define a numeric system that can only represent even/odd/prime/... numbers, in other words a dedicated type that is a subset of integral numbers; 如果你定义一个只能表示偶数/奇数/素数/ ...数字的数字系统,换句话说,一个专用类型是整数的子集,该怎么办?
  • if you define some kind of "fixed-point number" that represents half and full numbers, in that case not all numbers are enumerated; 如果你定义某种代表半数和全数的“定点数”,那么不是所有数字都是枚举的; and
  • the problem is most severe for floating point numbers . 浮点数问题最严重。

First of all, it means that [2.0 :: Float .. 3.0 :: Float] (used :: Float to make sure the call is not ambiguous) only contains integral values added to the original value, whereas if one uses this expression he/she might expect the list will include all floating points between the two values; 首先,它意味着[2.0 :: Float .. 3.0 :: Float] (使用:: Float来确保调用不模糊)只包含添加到原始值的整数值,而如果使用这个表达式他/她可能希望列表中包含两个值之间的所有浮点数; of course this argument is more about what one prefers. 当然,这个论点更多的是人们喜欢什么。 Most programmers don't have much problems with this aspect. 大多数程序员在这方面没有太多问题。

More severely, if one uses the expression [2.2 :: Float .. 4.0 :: Float] it results in [2.2,3.2,4.2] what is 4.2 doing here? 更严重的是,如果使用表达式[2.2 :: Float .. 4.0 :: Float]它会导致[2.2,3.2,4.2] 4.2在这里做什么?

If one uses a floating point number where +1 cannot generate a different number (because the mantissa doesn't have enough bits to represent one anymore), it will loop infinitely. 如果使用浮点数,其中+1不能生成不同的数字(因为尾数没有足够的位来代表一个),它将无限循环。 For instance: 例如:

Prelude> [1e37 :: Float .. 1e37 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.
Prelude> [1e37 :: Float .. 1e37-1 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.
Prelude> [1e37 :: Float .. 1e37+1 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.
Prelude> [1e37 :: Float .. pred 1e37 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.

One thus generates an infinite amount of values, even if the list ought to be empty or contain a few elements. 因此,即使列表应该为空或包含一些元素,也会产生无限量的值。

Part of the arguments are indeed a bit nitpicking, but at least for some, it is reasonable to assume that a Haskell programmer will eventually make mistakes. 部分论点确实有点挑剔,但至少对某些人来说,假设Haskell程序员最终会犯错误是合理的。

Wouldn't a more reasonable approach have been to generate the next representable floating point number? 生成下一个可表示的浮点数是不是更合理的方法?

What were the arguments to define succ in such way? 以这种方式定义succ的论据是什么? Is it reasonable that Float is an instance of Enum ? FloatEnum一个例子是否合理?

The origin of the succ function itself actually has nothing to do with the Haskell data types or enumerations, in fact the succ function came first. succ函数本身的起源实际上与Haskell数据类型或枚举无关,实际上succ函数首先出现。 The succ function is actually the successor function in the axiom of infinity which allows us to create numbers in the first place . succ函数实际上是无穷大公理中后继函数,它允许我们首先创建数字 It was never designed to be used with floating point/non-natural numbers, that's why you're encountering this problem. 它从来没有设计用于浮点数/非自然数,这就是你遇到这个问题的原因。

It would probably be a good idea to modify the succ function for floating point types in Haskell, you ought to submit something to the mailing list about it. 在Haskell中修改浮点类型的succ函数可能是个好主意,你应该向邮件列表提交一些关于它的东西。 Although, Haskell is standardized in the Haskell98 report so don't get your hopes up about changing the language. 虽然Haskell在Haskell98报告中是标准化的,所以不要对改变语言抱有希望。

Only read the following if you are familiar with Haskell's type classes: You mention different possible uses of the succ function, this is why it is defined as a function for the Enum type class. 如果您熟悉Haskell的类型类,请阅读以下内容:您提到了succ函数的不同可能用法,这就是为什么它被定义为Enum类型类的函数。 Therefore you can easily rebind it to do something different with a newtype . 因此,您可以轻松地重新绑定它以使用newtype执行不同的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM