oPo*_*olo 3 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
Run Code Online (Sandbox Code Playgroud)
这里的问题是:FS0039: The namespace or module 'bs' is not defined.
这怎么可能?毕竟bs在函数签名中.而且,在let bsLength = bs.Length工作之前定义一个新的值match.但通过这样做,我看到了一个新的怪异:
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
Run Code Online (Sandbox Code Playgroud)
这里的问题是一个警告说:warning FS0026: This rule will never be matched.我根本不明白.i并且数组的长度彼此无关.如果我写一个整数(例如10)而不是bsLength,则警告消失.
您的问题都来自于期望模式匹配允许交替使用值和文字.不,不是的.MSDN上的模式匹配(F#)主题很好地概述了其应用程序支持的模式类型和优先级规则.简化冗长描述的主要原则是:除非此值是文字或标识符(区分联合的案例值,异常标签或活动模式案例),否则无法匹配值.
在您的第一个问题点编译器不像您期望的那样将数据bs.Length视为Length数组的属性bs,而是视为Length来自不存在的模块或命名空间的文字或标识符bs; 正如John Palmer在他的回答中指出的那样,你可以通过使用带有保护语句的变量模式来实现预期的行为.合法使用类似于您的模式匹配表达式的示例将是:
module bs =
[<Literal>]
let Length = 100
//.............................
let v = 100;
let s = match v with
| bs.Length -> "matched"
| _ -> "not matched";;
val s : string = "matched"
Run Code Online (Sandbox Code Playgroud)
编译器将第二个问题点视为变量模式,并为其bsLength分配值i而不是正如您所期望的值进行比较; 第二个匹配规则没有机会进入.
匹配语句不像您认为的那样工作 - 正确的语法是
match i with
| t when t = bs.Length
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,您实际上创建了一个新变量bsLength,该变量隐藏了前面的定义bsLength并匹配所有整数,因此您可以获得规则永不匹配的警告.