我对函数式编程很陌生,我已经开始查看match
语句的文档,并在我遇到的示例gitpages中剪切并粘贴到下面的问题:< / p>
let rec fib n =
match n with
| 0 -> 0
| 1 -> 1
| _ -> fib (n - 1) + fib (n - 2)
我理解let
用于静态绑定,在这种情况下是一个名为fib的递归函数,它接受一个参数n。它试图匹配n与3个案例。如果它是0,1或其他任何东西。
我不明白在这种情况下调用|
符号或使用它的原因是什么?我搜索的关于f-sharp管道的任何东西都把我带到了|>
,这是f sharp中的管道特征。
在这种情况下,|
用于什么?它是必需的还是可选的?什么时候应该而且不应该使用|
?
答案 0 :(得分:6)
|
符号用于F#中的多个内容,但在这种情况下,它用作match
构造的案例的分隔符。
match
构造允许您对某些输入进行模式匹配,并以不同方式处理不同的值 - 在您的示例中,您有0
的一个案例,1
的一个案例和一个案例所有其他价值观。
通常,match
的语法如下所示:
match <input> with <case_1> | ... | <case_n>
每个<case>
具有以下结构:
<case> = <pattern> -> <expression>
此处,|
符号只是分隔模式匹配表达式的多个案例。然后,每个case都有一个模式和一个表达式,当输入与模式匹配时,它将被计算。
答案 1 :(得分:4)
为了扩展Tomas的优秀答案,以下是F#中|
的各种用法:
在match expressions中,|
将各种模式分开,正如托马斯指出的那样。虽然您可以将整个match
表达式写在一行上,但是将每个模式写在一个单独的行上,排列|
个字符是常规的,这样它们就形成了一个可视指示符。 match
声明的范围:
match n with
| 0 -> "zero"
| 1 -> "one"
| 2 -> "two"
| 3 -> "three"
| _ -> "something else"
Discriminated Unions(或者DUs,因为输入的时间要短很多)与样式中的match
表达式非常相似:定义它们意味着列出可能性,而|
是用于分离可能性。与match
表达式一样,您可以(如果您愿意)在一行上写入DU:
type Option<'T> = None | Some of 'T
但除非您的DU只有两种可能性,否则通常最好将它写在多行上:
type ContactInfo =
| Email of string
| PhoneNumber of areaCode : string * number : string
| Facebook of string
| Twitter of string
在这里,|
最终形成了一条垂直线,吸引了DU的可能性,并且非常清楚DU定义的结束位置。
Active patterns也使用|
来分隔各种可能性,但它们也包含在一对开始和结束的|
字符中:
let (Even|Odd) n = if n % 2 = 0 then Even else Odd // <-- Wrong!
let (|Even|Odd|) n = if n % 2 = 0 then Even else Odd // <-- Right!
活动模式通常以我刚刚显示的方式编写,|
会立即出现在括号内,这就是为什么有些人会谈论&#34;香蕉剪辑&#34; (因为(|
和|)
对看起来像香蕉,如果你运用你的想象力)。但实际上,没有必要将(|
和|)
个字符拼写在一起:将括号与|
字符分开的空格完全有效:
let (|Even|Odd|) n = if n % 2 = 0 then Even else Odd // <-- Right!
let ( |Even|Odd| ) n = if n % 2 = 0 then Even else Odd // <-- ALSO right!
管道运算符|>
和布尔运算符||
与|
运算符的使用完全不同。 F#允许运算符为符号的任意组合,并且它们与看起来几乎相同的运算符具有非常不同的含义。例如,>=
是标准运算符,表示&#34;大于&#34;。许多F#程序将定义自定义运算符>>=
。但是虽然在F#核心库中没有定义>>=
,但它具有标准含义,并且标准含义不是&#34;比&#34;大很多。相反,>>=
是为bind
函数编写运算符的标准方法。我现在还没有进入bind
所做的事情,因为这个概念可以自行完成整个答案。但是,如果您对bind
的工作原理感到好奇,可以阅读Scott Wlaschin's series on computation expressions,这很好地解释了这一点。