【问题标题】:F# type matching with ":? Type as name": why do we need a new name?F# 类型匹配“:?Type as name”:为什么我们需要一个新名称?
【发布时间】:2023-04-07 22:26:01
【问题描述】:

我正在查看此处描述的 F# 中类型的模式匹配语法:

http://msdn.microsoft.com/de-de/library/dd547125.aspx#sectionToggle14

该页面的示例(稍作修改):

open System.Windows.Forms

let RegisterControl (control: Control) =
    match control with
    | :? Button as button -> button.Text <- "Registered."
    | :? CheckBox as checkbox -> checkbox.Checked <- false
    | _ -> ()

我不明白为什么我们需要在类型检查的同时引入一个新名称(“按钮”、“复选框”)。如果匹配成功,编译器应该知道“控制”具有所需的类型,并且可以在以下表达式/语句中相应地处理它。换句话说,为什么我不能这样做:

open System.Windows.Forms

let RegisterControl (control: Control) =
    match control with
    | :? Button -> control.Text <- "Registered."
    | :? CheckBox -> control.Checked <- false
    | _ -> ()

这类似于"type guard" feature in TypeScript 1.4

F# [还] 不这样做有充分的理由吗? (注意:我正在运行 VS 2012。)

【问题讨论】:

    标签: .net f# pattern-matching


    【解决方案1】:

    您需要一个新名称的一个明显原因是match 的参数是一个表达式:

    match some.Method() with
    | :? Button -> // What to do here??
    

    当然,语言可以支持符号。在这种情况下,你不能这样做没有技术原因,但我认为不这样做有一个很好的合乎逻辑的理由。

    F# 中的每个值都有一个显式声明的位置(当你使用一个值时,你总是可以去定义)。使用这种简化的:? Type 语法定义的值实际上并没有任何声明

    • 你可以说它们是在声明原始变量的地方声明的,但这是错误的 - 因为在那里,它会有不同的类型。

    • 或者您可以说它们是以某种“隐藏方式”声明的,但这会为该语言引入一个全新的概念。

    也就是说,我明白为什么语法很好而且有用。但它似乎不太适合 F# 中变量如何工作的逻辑。

    【讨论】:

    • 确实,这很明显。猜我太专注于例子了。谢谢。
    • 示例驱动的语言设计 :-)
    • 示例驱动的语言理解,不可避免的愚蠢问题 :) 我不敢仅仅基于示例进行语言设计,保证。
    • @MoritzBeutel 该评论不是针对您,而是针对 TypeScript 团队! :-)
    【解决方案2】:

    这将用一致的模型换取不一致的模型。

    您需要引入一个新名称并不完全正确。这很好用:

    match control with
    | :? Button -> doButtonyStuff control
    | :? CheckBox -> doCheckBoxyStuff control
    | _ -> ()
    

    当然,您的 control 值在匹配案例正文中保持为 Control 除外。仅当您想在匹配模式中进行类型检查(C#-style is)和强制转换(C#-style as)时才引入名称。

    您的建议可以很容易地想象为您在比赛中使用的control: Control 在演员阵容后与另一个control: Button 的隐式阴影。我看到的一个问题是它具有使control: Control 在匹配案例主体中无法访问的附带效果。在您的特定示例中这可能没什么大不了的,但是如果您要检查接口类型,它可能会变得笨拙。

    今天没有模式匹配结构做这样隐含的事情。除非您自己这样做,否则您的绑定不会受到影响。如果你问我,那很好。显式优于隐式。

    【讨论】:

    • 我认为接口的情况不是问题,因为 .NET 泛型具有相似的语义:您可以将类型参数约束为任意类型并实现多个接口,编译器将根据请求的用法,将类型的变量视为类型或接口之一。
    • 这肯定比 Button vs Control 的例子更成问题。在 F# 中,接口仅显式实现,因此要访问接口方法,您需要转换为接口类型(此时您不再可以访问非接口方法,您需要转换回具体类型)。 Button 可能会重新暴露 Control 提供的所有重要内容,这样就不会那么痛苦了。
    猜你喜欢
    • 2013-12-03
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2019-06-09
    相关资源
    最近更新 更多