【问题标题】:Why are there Uppercase Named Patterns in F#?为什么 F# 中有大写命名模式?
【发布时间】:2017-04-17 14:00:05
【问题描述】:

The F# 4.0 Language Specification,它说:

7.2 命名模式

如果 long-ident 长度超过一个字符或以大写字符开头(即,如果 System.Char.IsUpperInvarianttrue 并且 System.Char.IsLowerInvariant 在第一个字符上是 false),它通过使用模式中的 名称解析来解决(第 14.1.6 节)。该算法产生以下之一:

  • 联合案例
  • 异常标签
  • 活动模式案例名称
  • 文字值

所以下面的代码不起作用:

[<Literal>]
let zero = 0

let matchZero = function
    | zero -> printfn "Is %A" zero
    | _ -> printfn "Not 0"

zero 应该与模块一起使用,或者有第一个大写字母Z

module Match =
    [<Literal>]
    let zero = 0

let matchZero = function
    | Match.zero -> printfn "Is %A" Match.zero
    | _ -> printfn "Not 0"

///////////////////////////////////////
///////////////////////////////////////

[<Literal>]
let Zero = 0

let matchZero = function
    | Zero -> printfn "%A" Zero
    | _ -> printfn "Not 0"

为什么文字 zero 必须有第一个大写字母才能正常工作?

【问题讨论】:

    标签: .net f# functional-programming pattern-matching ocaml


    【解决方案1】:

    这就是语言的设计方式。问“为什么”是没有用的,除了编译器说它必须这样做之外,没有其他根本原因。

    该决定背后的基本原理可能如下:在匹配模式时,编译器需要以某种方式确定您是在尝试匹配特定值还是匹配 any em> 值并将其绑定到名称。考虑以下几点:

    match 1 with
    | zero -> printfn "Zero!"
    | x -> printfn "Got a value: %d" x
    

    xzero 在这种情况下的主要区别是什么?对于编译器来说,它们看起来完全一样。那么当编译器需要决定是生成if 1 = zero then printfn "Zero!"这样的代码还是生成let x = 1; printfn "Got a value: %d" x这样的代码时,做出这个决定的依据是什么?如何区分x 案例和zero 案例?

    因此,发明了一个人为的基础:如果模式是大写的,那么它就是zero-case,如果它以小写字符开头,那么它就是x-case。

    注意:当文字位于模块内部时,这种歧义根本不会出现,因为只有一种方法可以解释包含点的模式。

    问:但是编译器不能只看上面是否真的定义了zero,然后据此做出决定吗?

    答:嗯,是的,它可以(事实上,这正是它的作用,这就是你收到编译时警告的原因),但这会导致无法预料的后果:当你首先编写匹配项,您已经定义了zero,并且match 表达式将只匹配零。但是在您的程序演化的后期,有人出于某种原因决定删除zero,现在match 表达式将匹配任何内容,并且不会产生任何编译时错误!你会有一个微妙的错误,编译器不会捕捉到它,所以你唯一的希望是你的单元测试或质量检查人员。防止这种事情发生是非常值得的强制命名实践的小不便。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多