F#奇数模式匹配问题

时间:2013-06-24 10:08:47

标签: f# pattern-matching

在昨天编写一些代码时,我遇到了两个奇怪的问题,我和我的函数式编程导向的朋友都不知道。我们已经看了很长时间,并在网上研究过它,但我们无法在任何地方找到任何答案,所以这里有:

问题在于此代码:

第一个奇怪的问题:

let outer1 (bs : byte array) =
    let rec inner (bs : byte array) (bacc : byte array) (i : int) =
        match i with
        | bs.Length -> bacc // <--- Error: bs is not recognized. Why?
        | _ -> bacc.[i] <- bs.[i]
               inner bs bacc (i + 1)
    inner bs (Array.zeroCreate bs.Length) 0

这里的问题是:FS0039: The namespace or module 'bs' is not defined. 怎么会这样?毕竟bs在函数签名中。此外,使用let bsLength = bs.Length定义新值的工作正好在match之前。但通过这样做,我看到了一个新的奇怪之处:<​​/ p>

let outer2 (bs : byte array) =
    let rec inner (bs : byte array) (bacc : byte array) (i : int) =
        let bsLength = bs.Length
        match i with
        | bsLength -> bacc
        | _ -> bacc.[i] <- bs.[i] // <--- Warning: Rule never matched. Why?
               inner bs bacc (i + 1)
    inner bs (Array.zeroCreate bs.Length) 0

此处的问题是警告:warning FS0026: This rule will never be matched。 我根本不明白。 i并且数组的长度彼此无关。如果我写一个整数(例如10)而不是bsLength,警告就会消失。

2 个答案:

答案 0 :(得分:8)

您的问题都来自于期望模式匹配允许交替使用值和文字。不,不是的。 MSDN上的Pattern Matching (F#)主题很好地概述了其应用程序支持的模式类型和优先级规则。简化冗长描述的主要原则是:除非此值为文字标识符(区分联合的案例值,异常标签),否则您无法匹配值,或活动模式案例。)

在您的第一个问题点中,编译器不会将bs.Length视为数组Length的属性bs,而是将其视为不存在的文字或标识Length模块或命名空间bs;正如John Palmer在他的回答中指出的那样,通过使用带有guard statement变量模式,您可以实现预期的行为。合法使用类似于你的模式匹配表达式的样本将是:

module bs =
    [<Literal>]
    let Length = 100
//.............................
let v = 100;
let s = match v with
    | bs.Length -> "matched"
    | _ -> "not matched";;

val s : string = "matched"

编译器将第二个问题点视为变量模式,并为bsLength分配值i,而不是像您预期的那样比较值;第二个匹配规则没有机会参与。

答案 1 :(得分:6)

匹配语句不像您认为的那样工作 - 正确的语法是

match i with
| t when t = bs.Length

在第二种情况下,您实际创建了一个名为bsLength的新变量,该变量隐藏了早期bsLength的定义并匹配所有整数,因此您可以获得规则永不匹配的警告。