2013-06-24 74 views
3

昨天写了一些代码时,我遇到了两个奇怪的问题,这两个问题都不是我和我的功能性编程导向的朋友都知道的。我们看着它在相当一段时间,并研究它在网络上,但我们没能在别处找到任何答案,所以这里有云:F#奇数模式匹配问题

的问题是,在此代码:

天下第一问题:

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在函数签名中。此外,在match之前let bsLength = bs.Length定义一个新值。但这样做我看到一个新的怪胎:

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,则警告消失。

回答

8

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

在你的第一个问题点编译器将bs.Length不是作为一个属性数组bsLength像您期望的,但作为一个文字或不存在的模块或命名空间bs标识Length;因为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而不是被比较的值的值,如你所料;第二个匹配规则没有机会踢。

+0

谢谢,清除它。我现在更改了代码,并且它可以工作。此外,现在很高兴终于明白问题所在。你的好回答。 :) – oPolo

6

像你认为它的匹配语句不工作 - 正确的语法是

match i with 
| t when t = bs.Length 

在第二种情况下,实际上创建了一个名为bsLength新的变量,它隐藏的早期bsLength的定义和匹配所有整数,所以你得到的规则从来没有匹配的警告。

+0

谢谢,一个简单但重要的答案。 :) 好答案!清理它,我知道现在的问题,这要归功于它在那里创建一个新变量的知识。 :) – oPolo