【问题标题】:What is the | symbol for in f #?什么是| f # 中的符号?
【发布时间】:2017-06-29 10:15:01
【问题描述】:

我是函数式编程的新手,我已经开始查看match 语句的文档,在示例中我遇到了gitpages 并剪切并粘贴到下面的问题中:

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 中的管道字符。

在这种情况下,| 是做什么用的?它是必需的还是可选的?什么时候应该和不应该使用|

【问题讨论】:

  • 谢谢,总结一下我学到的|被称为香蕉夹,它所属的语句或函数称为主动识别器,这意味着在每个语句上面的函数中是一个主动模式,函数是一个主动识别器。这是正确的@flaZer 吗?
  • 根据链接,您好像少了一块。 “match n with”中的“n”似乎是您在代码示例中未提供的函数......所以在上面的示例中也似乎是“|”引用看起来像一个“switch”语句,基于输出函数“n”。
  • 但我只是根据我找到的链接猜测 - 我不知道 f#
  • 基于链接,我认为我是对的,但我会保持打开状态,以便确保我以正确的方式处理此问题。如果在我的理解中存在知识差距,我希望将其关闭。

标签: f#


【解决方案1】:

| 符号在 F# 中用于多种用途,但在本例中,它用作 match 构造的大小写分隔符。

match 构造允许您对某些输入进行模式匹配并以不同的方式处理不同的值 - 在您的示例中,0 有一种情况,1 有一种情况,所有其他值都有一种情况。

一般来说,match 的语法是这样的:

match <input> with <case_1> | ... | <case_n>

其中每个&lt;case&gt; 具有以下结构:

<case> = <pattern> -> <expression>

这里,| 符号只是将模式匹配表达式的多个情况分开。然后,每个案例都有一个模式和一个表达式,当输入与该模式匹配时评估该表达式。

【讨论】:

    【解决方案2】:

    为了扩展 Tomas 的出色答案,这里有更多 | 在 F# 中的各种用法:

    匹配表达式

    正如 Tomas 所指出的,在match expressions 中,| 将各种模式分开。虽然您可以将整个 match 表达式写在一行上,但按照惯例,将每个模式写在单独的行上,将 | 字符对齐,这样它们就可以形成match 语句范围的可视指示符:

    match n with
    | 0 -> "zero"
    | 1 -> "one"
    | 2 -> "two"
    | 3 -> "three"
    | _ -> "something else"
    

    歧视性工会

    Discriminated Unions(或 DU,因为它的类型要短得多)在风格上与 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!
    

    活动模式通常以我刚刚展示的方式编写,| 立即出现在括号内,这就是为什么有些人谈论“香蕉剪辑”(因为 (||) 对看起来像香蕉如果你发挥你的想象力)。但实际上,(||) 字符没有必要一起写:用空格将括号与 | 字符分开是完全有效的:

    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!
    

    无关的事情

    管道运算符|&gt; 和布尔或运算符||| 运算符的使用完全不同。 F# 允许运算符是符号的任意组合,并且它们与看起来几乎相同的运算符具有非常不同的含义。例如,&gt;= 是一个标准运算符,意思是“大于”。许多 F# 程序将定义一个自定义运算符&gt;&gt;=。但是,虽然&gt;&gt;= 没有在 F# 核心库中定义,但它具有标准含义,并且该标准含义不是“远大于”。相反,&gt;&gt;= 是为bind 函数编写运算符的标准方法。我不会深入探讨bind 现在所做的事情,因为这是一个可以独自完成整个答案的概念。但如果您对bind 的工作原理感到好奇,您可以阅读Scott Wlaschin's series on computation expressions,它很好地解释了这一切。

    【讨论】:

    • 非常感谢您的解释!
    • @KazRodgers 另外值得一提的是| 是“或”模式,当在单个模式中使用时,例如match x with 0 | 1 -&gt; "zero or one" | 2 | 3 -&gt; "two or three"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2012-04-19
    • 2015-12-20
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 2011-03-20
    相关资源
    最近更新 更多