11

我刚刚注意到 F# 允许我将 let 绑定与文字和其他模式一起使用,如下所示:

let fib 0 = 1
let exists item [] = false
let car (hd :: tl) = hd
let cdr (hd :: tl) = tl

F# 正确地将这些函数解释为一种模式匹配,因为给了我以下警告:

警告 1 此表达式的模式匹配不完整。例如,值 '1' 将不匹配

警告 2 此表达式的模式匹配不完整。例如,值“[_]”将不匹配

等等

这些函数按预期工作,但我想以这种样式定义一个具有完整模式匹配的函数,但是我在 F# 手册中找不到关于这种替代模式匹配语法的任何信息。

我知道我可以使用let whatever = function ...let whatever x = match x with ...获得我想要的结果,但是我刚刚发现了另一种模式匹配语法,如果我不知道如何使用它,它会一直困扰着我。

如何使用上面显示的替代模式匹配语法编写函数?

4

4 回答 4

12

AFAIK,在 F# 中无法声明具有相同名称和不同模式匹配签名的多个 let 绑定。我相信与您正在寻找的最接近的构造是函数规则表达式。

以汽车为例

let car = function
    | hd::tl -> hd
    | [] -> failwith "empty list"
于 2009-01-18T18:25:07.953 回答
9

JaredPar 是对的,F# 没有 Haskell 在这里所做的语法形式。

F# 形式对于打破开放的单案例区分联合或定义具有不完全匹配的函数(例如在空列表上失败的“汽车”示例)非常有用。这只是语言中几乎所有名称绑定都是通过模式完成的事实的结果。由于您描述的确切原因,这种语法形式(使用参数模式定义函数)在实践中通常不太有用。

我认为 Haskell 在句法形式方面比 ML 做得更好,但 F# 的根源在于 ML。好处是 F# 的一个很好的子集可以与 OCaml 交叉编译(这有助于引导 F# 语言和用户社区);缺点是 F# 被一些丑陋/有限的语法“卡住”。

于 2009-01-18T19:46:35.933 回答
8

显然,F# 的模式匹配比我们在普通开发中使用的要强大得多。

首先,您可以一次绑定多个值。通常,您将使用List.partition

let data = [7;0;0;0;1;0;1;1;1;1;0;0;1;1;0]
let ones, others = data |> List.partition ((=) 1) // bind two values

作为旁注,您可以将多个标识符绑定到相同的值:

let (a & b) = 42 // a = 42; b = 42

let为了简单起见,让我们从一个简单的绑定开始。

let hd::tl = data

警告 FS0025:此表达式的模式匹配不完整。例如,值“[]”可能表示模式未涵盖的情况。

为了缓解这种情况,我们必须为空列表添加另一个案例:

let (hd::tl) | [] = data

错误 FS0018:此“或”模式的两侧绑定不同的变量集

这是真的;如果列表为空,则hd保持tl未绑定。很容易绑定tl同一个空列表:

let (hd::tl) | ([] as tl) = data

但是,错误错误 FS0018并没有消失。事实上,我们还必须为hd.
以下肮脏的技巧将做到这一点。

let (hd::tl, _) | ([] as tl , hd) = data, 42

上面的行将绑定hddata的头部,以防列表不为空,或者使用tuple.

注意我还没有找到嵌入42let构造中的方法。

最后,car功能相同:

let car ((hd::tl, _) | ([] as tl, hd)) = hd
let foo = car(data, 42) // foo = 7
let bar = car([], 42)   // bar = 42
于 2012-12-21T22:33:49.747 回答
1

如何使用上面显示的替代模式匹配语法编写函数?

正如您所拥有的,但仅当一种模式详尽无遗时。这很有用的明显示例包括元组和记录以及单例联合和活动模式。

每当您执行以下操作时,您都会使用此语言功能:

let f(a, b) = ...

所以这概括为:

let f(a, (b, c)) = ...

您甚至可以使用它来选择默认值或Some value

let def(x, None | _, Some x) = x

顺便说一句,您建议的样式在 Haskell 之前已在 SML 中使用,而 SML 是一种 ML,因此这显然与 Haskell vs ML 无关。我实际上更喜欢 OCaml/F# 样式,因为它的重复性较低:

fun descriptiveFunctionName [] = true
fun descriptiveFunctionName (_::_) = false

对比

let descriptiveFunctionName = function
  | [] -> true
  | _::_ -> false

这对于使用自文档标识符具有真正价值的非学术代码来说更好。

于 2012-12-16T14:32:46.530 回答