F# F中带浮点(双类型)的模式匹配#

F# F中带浮点(双类型)的模式匹配#,f#,floating-point,pattern-matching,double,F#,Floating Point,Pattern Matching,Double,有人能解释为什么F#似乎不喜欢模式加工表达式中的float(type Double)吗 让intDiv x y= 将x/y与 |5->printfn“结果是五个祝贺”;5. |z->printfn“结果是另一个:%i”z;Z 匹配inttype:按预期工作 让floatDiv x y= 将x/y与 |nan->printfn“伙计,你到底做了什么?”;楠 |无限->打印fn“哇,你得到了无限!”;无穷 |5.0->printfn“结果是5-为你感到骄傲”;5 |z->printfn“结果是另一

有人能解释为什么F#似乎不喜欢模式加工表达式中的float(type Double)吗

让intDiv x y=
将x/y与
|5->printfn“结果是五个祝贺”;5.
|z->printfn“结果是另一个:%i”z;Z
匹配
int
type:按预期工作

让floatDiv x y=
将x/y与
|nan->printfn“伙计,你到底做了什么?”;楠
|无限->打印fn“哇,你得到了无限!”;无穷
|5.0->printfn“结果是5-为你感到骄傲”;5
|z->printfn“结果是另一个:%i”z;Z
这里匹配的case
nan
每次都会匹配,编译器也会警告我这一点,但是,它似乎也会返回正确的结果。我只希望它与最后一个案例相匹配

>floatDiv 10。3.
伙计,你到底做了什么?
val it:float=3.333

正如您所观察到的
nan
infinity
在这里被视为标识符,并且值与它们绑定

如果检查F#规格:

第7章(第115页)说,
const
表达式是一种模式

第4章(第36页)说,
const
包括
ieee64

第3章(第29页)说,
ieee64
要么是一个
float
,要么是一个后跟
LF

在示例位置,我们找到了
float
的定义

token float =        
   digit+ . digit*         
   digit+ (. digit* )? (e|E) (+|-)? digit+  
此定义仅适用于123、3.14、1E99等情况。它不包括无穷大和nan

因此,根据规范,上述行为是预期的。应该改变吗?但可能需要更新语言,将nan和infinity作为float常量表达式的一部分。由于ieee确实包含了这些值,所以我认为它应该是常量表达式的一部分

然而,这种更改可能有风险,因为在旧代码
nan
中突然意味着对方法的引用,随着更改,它将是一个浮点文本。也许有人用nan作为函数名?这将导致崩溃,因为这就像给一个函数命名:
0

正如@傻瓜所提到的,您可以使用活动模式来解决这个问题

// Define the Active Pattern
let (|Float|Infinity|NaN|) n =
  if System.Double.IsPositiveInfinity   n then Infinity true
  elif System.Double.IsNegativeInfinity n then Infinity false
  elif System.Double.IsNaN              n then NaN
  else Float n

// We can then use the Active Pattern as a "smart" pattern
let floatDiv x y =
  match x / y with
  | NaN          -> printfn "Homie, what did you even do?"; nan
  | Infinity _   -> printfn "Wow, you got infinity!"; infinity
  | Float    5.0 -> printfn "Result was 5 - proud of you"; 5.0
  | Float    z   -> printfn "Result was something else: %f" z; z

let run () =
  floatDiv 1.0 2.0 |> printfn "%A"
  floatDiv 5.0 1.0 |> printfn "%A"
  floatDiv 1.0 0.0 |> printfn "%A"
  floatDiv 0.0 0.0 |> printfn "%A"
将浮点数与特定的数字进行比较总是有点“危险”,因为浮点数的性质通常只是一个近似的答案。通常将结果与公差范围进行比较

此外,;nan使许多开发人员感到困惑,因为大多数涉及nan的比较都是错误的

1.0 < nan // false  <-|
nan < 1.0 // false, <-| these inequalities can break balanced trees algorithms if you use float as a key and happen to insert a nan

nan = nan  // false  <-|
nan <> nan // true   <-| perhaps also surprising?

1.0nan
匹配为变量名,而不是浮点常量。这是语言中bug的预期行为吗?您需要这样的东西:let(| NaN | | |)value=如果Single.IsNaN value,那么Some()其他无