Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Syntax 如何在';让';定义?_Syntax_F#_Pattern Matching - Fatal编程技术网

Syntax 如何在';让';定义?

Syntax 如何在';让';定义?,syntax,f#,pattern-matching,Syntax,F#,Pattern Matching,我刚刚注意到,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绑定,如下所示:

let fib 0 = 1
let exists item [] = false
let car (hd :: tl) = hd
let cdr (hd :: tl) = tl
F#正确地将这些函数解释为一种模式匹配,因为它给了我以下警告:

警告1模式匹配不完整 在这个表达式上。例如 值“1”将不可用 匹配

警告2模式匹配不完整 在这个表达式上。例如 值“[\]”将不会被删除 匹配

等等

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

我知道我可以使用
let which=function…
let which x=match x与…
来获得我想要的结果,但我刚刚发现了另一种模式匹配语法,如果我不知道如何使用它,它将永远困扰着我


如何使用上面所示的可选模式匹配语法编写函数?

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

以汽车为例

let car = function
    | hd::tl -> hd
    | [] -> failwith "empty list"
JaredPar是对的,F#没有Haskell在这里使用的语法形式

F#形式主要用于断开区分大小写的联合或定义不完全匹配的函数(如空列表中失败的“car”示例)。这仅仅是因为语言中几乎所有的名称绑定都是通过模式完成的;这种语法形式(使用参数模式定义函数)在实践中通常不太有用,原因正是您所描述的


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

如何使用上面显示的可选模式匹配语法编写函数

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

无论何时执行以下操作,都可以使用此语言功能:

let f(a, b) = ...
因此,这概括为:

let f(a, (b, c)) = ...
您甚至可以使用此选项在默认值或某个值之间进行选择:

let def(x, None | _, Some x) = x
顺便说一句,您建议的样式在Haskell之前在SML中使用,SML是ML,因此这显然与Haskell vs ML无关。我实际上更喜欢OCaml/F#样式,因为它重复性较少:

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

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

显然,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
let (hd::tl) | ([] as tl) = data
错误FS0018:此“或”模式的两侧绑定不同的变量集

这是真的;如果列表为空,
hd
tl
保持未绑定状态。使用相同的空列表绑定
tl
很容易:

let (hd::tl) | [] = data
let (hd::tl) | ([] as tl) = data
但是,错误FS0018不会消失。实际上,我们还必须为
hd
提供一些“默认”值
下面的肮脏伎俩可以做到这一点

let (hd::tl, _) | ([] as tl , hd) = data, 42
如果列表不是空的,
hd
将绑定到
数据的头上,将在
元组的第二个值中提供额外的值

注意我没有找到将
42
嵌入
let
结构的方法

最后,对于
汽车
功能也一样:

let car ((hd::tl, _) | ([] as tl, hd)) = hd
let foo = car(data, 42) // foo = 7
let bar = car([], 42)   // bar = 42

这正是我的假设,尽管F#不支持Haskell风格的模式匹配让我感到惊讶:)“我认为Haskell在很多方面都比ML做得更好”。这是SML对OCaml。与Haskell无关,Haskell只是在这方面复制了SML。默认值给定的更好解决方案(对于注释之前的版本,它看起来更好)是定义
let(|Id|)x_=x
let(| Wrap |)fx=fx
,然后
let((Wrap Some hd)::tl)|([]&tl&Id None hd)=data
。它给出了一个错误的
FS0025
,我还没有时间找到一个好方法来删除它。很酷的例子!谢谢