F#beginner here。
我正在尝试将元组与几个案例匹配,并在匹配条件上返回特定值。这是它的外观:
match inf, sup with
| nan , _
| _ , nan
-> Interval(nan,nan)
| _ , _ when inf = -infinity && sup = -infinity -> Interval(nan,nan)
| _ , _ when inf = infinity && sup = infinity -> Interval(nan,nan)
| _ , _ when inf > sup -> Interval(nan,nan)
| _ , _ -> Interval(inf,sup)
由于几乎每个案例都返回Interval(nan,nan),我想将它们归为可读性,但我不知道如何。我尝试了以下
match inf, sup with
| nan , _
| _ , nan
| _ , _ when inf = -infinity && sup = -infinity
| _ , _ when inf = infinity && sup = infinity
| _ , _ when inf > sup -> Interval(nan,nan)
-> Interval(nan,nan)
| _ , _ -> Interval(inf,sup)
但是编译器说
这个'或'模式的两面绑定不同的varibales
所以我尝试了以下内容:
match inf, sup with
| nan , _
| _ , nan
-> Interval(nan,nan)
| _ , _ when inf = -infinity && sup = -infinity
| _ , _ when inf = infinity && sup = infinity
| _ , _ when inf > sup -> Interval(nan,nan)
-> Interval(nan,nan)
| _ , _ -> Interval(inf,sup)
这里我在第二个错误中得到错误从第二个时间条款。他期待一个' - >'或其他令牌。
那么:我如何缩短这种匹配或如何改进它?那些几个Interval(nan,nan)对我来说似乎是不必要的。
提前致谢!
答案 0 :(得分:5)
您没有正确检查nan
。与nan
匹配将导致任何提供的值绑定到名为nan
的值。在FSI注意:
let isNan x = match x with |nan -> true |_ -> false;; let isNan x = match x with |nan -> true |_ -> false;; -----------------------------------------^ stdin(1,42): warning FS0026: This rule will never be matched
您应该使用nan
检查System.Double.IsNaN(x)
值。
考虑到这一点,我会使用活动模式来检查无效值:
let (|PositiveInfinity|NegativeInfinity|NaN|Real|) = function
|v when v = -infinity -> NegativeInfinity
|v when v = infinity -> PositiveInfinity
|v when System.Double.IsNaN(v) -> NaN
|v -> Real v
然后将模式匹配减少到:
let test inf sup =
match inf, sup with
|NaN, _
|_, NaN
|NegativeInfinity, NegativeInfinity
|PositiveInfinity, PositiveInfinity
|_, _ when inf > sup -> Interval(nan, nan)
|_, _ -> Interval(inf, sup)
答案 1 :(得分:3)
匹配语句when
子句对于之前列出的所有或案例都是通用的。如果你想要想象这个,你可以想到像这样的parens:
( | Case1 n
| Case2 n
| Case3 n ) when predicate(n) ->
在结果表达式之前(when
之后),您不能重复->
个句子几次。
相反,您可以在一个when
子句中加入所有条件,类似于:
| _ when cond1 ||
cond2 ||
cond3 -> ...
答案 2 :(得分:3)
@TheInnerLight给出的答案很棒,但处理角落的情况有所不同。 OP认为(-inf,10.0)之间的间隔是有效的,但是发布的答案没有。这是一个处理所有情况相同的答案:
let (|PositiveInfinity|NegativeInfinity|NaN|Real|) = function
| v when Double.IsPositiveInfinity v -> PositiveInfinity
| v when Double.IsNegativeInfinity v -> NegativeInfinity
| v when Double.IsNaN v -> NaN
| v -> Real v
let getInterval inf sup =
match inf, sup with
| NaN, _
| _ , NaN
| NegativeInfinity, NegativeInfinity
| PositiveInfinity, PositiveInfinity
| _ , _ when inf > sup -> Interval(nan,nan)
| _ , _ -> Interval(inf,sup)
稍微偏离主题:我通常建议不要使用NaN
作为无效间隔的标记。与NaN
的任何比较都返回false,这意味着您需要在每个间隔检查中以不同方式处理它们。考虑以下两个版本的写作“在一个区间内是一个点v
?”,其中下限和上限恰好是NaN
:
let inside1 v = v >= nan && v <= nan
let inside2 v = not (v < nan || v > nan)
在inside1
中,您检查“是内在的点?”,在inside2
中,您会问“它不在外面吗?”。检查点1.0给出:
> inside1 1.0;;
val it : bool = false
> inside2 1.0;;
val it : bool = true
因此,我建议您的函数返回Interval option
,在您目前返回None
的所有情况下都会返回Interval(nan,nan)
。否则,您的代码将被全部明确的NaN
检查所污染。
答案 3 :(得分:1)
只需在||
子句中使用布尔值或when
:
match inf, sup with
| nan , _
| _ , nan
-> Interval(nan,nan)
| _ , _ when inf = -infinity && sup = -infinity ||
inf = infinity && sup = infinity ||
inf > sup -> Interval(nan,nan)
| _ , _ -> Interval(inf,sup)