F#:使用区分联合解构绑定

Posted

技术标签:

【中文标题】F#:使用区分联合解构绑定【英文标题】:F#: Destructuring bind with a discriminated union 【发布时间】:2016-07-14 01:50:57 【问题描述】:
open System

let x = (1, 2)
let (p, q) = x
printfn "A %A" x
printfn "B %A %A" p q

let y = Some(1, 2)
try
  let None = y
  ()
with
  | ex -> printfn "C %A" ex
let Some(r, s) = y
printfn "D %A" y
// printfn "E %A %A" r s
http://ideone.com/cS9bK0

当我取消注释最后一行时,编译器会拒绝抱怨的代码

/home/rRiy1O/prog.fs(16,19):错误 FS0039:未定义值或构造函数“r” /home/rRiy1O/prog.fs(16,21): error FS0039: The value or constructor's' is not defined

在解构let时不允许使用枚举吗?

但首先,即使我注释掉最后一行......我在这里做什么 am?这是输出:

A (1, 2)
B 1 2
D Some (1, 2)

更新

为了记录,这里是固定版本:

open System

let x = (1, 2)
let (p, q) = x
printfn "A %A" x
printfn "B %A %A" p q

let y = Some(1, 2)
try
  let (None) = y
  ()
with
  | ex -> printfn "C %A" ex
let (Some(r, s)) = y
printfn "D %A" y
printfn "E %A %A" r s
http://ideone.com/7qL9mH

输出:

A (1, 2)
B 1 2
C MatchFailureException ("/home/MBO542/prog.fs",10,6)
D Some (1, 2)
E 1 2

完美。

【问题讨论】:

没有直接关系,但let None = y 行是否创建了一个名为 None 的新值? @MarkPattison \(^o^)/ 在 F# 中,应该避免重新定义 NoneSome,但现在看来,您正在以一种艰难的方式学习这一点。同样对于 .NET 和 F#,尤其要避免使用 try ... catch,因为它在时间上很昂贵。如果您需要捕获错误/异常,强烈考虑使用Option type 或更高级的场景Railway oriented programming 你能改一下标题吗,我没有看到枚举。 @GuyCoder 傻了我,我更新了标题。有区别的联合在 Rust 中被称为枚举,我花了很多时间。顺便说一句,try...catch 专门用于针对None 的非详尽模式匹配,这会产生异常(我在移动设备上,找不到它的确切名称。)我的意图不是重新定义None。您似乎误解了我提出这个问题的意图。 【参考方案1】:

你尝试解构y的方式:

let Some(r, s) = y

您实际上是在定义一个名为Some 的函数,它有两个参数rs,以元组形式传递。

为了正确解构,需要加括号:

let (Some (r, s)) = y

顺便说一句,try 块内也发生了同样的事情:let None = y 行创建了一个名为 None 的新值,等于 y

【讨论】:

Option 枚举的两种情况都编译得很好,但与我的意图背道而驰,这一事实让我非常沮丧。顺便问一下,您是如何获得这些知识的?根据经验,还是我错过了语言参考中的任何描述? 经验为王,当然。没有什么比实际用它做某事更能让人理解事物了。向他人解释也有助于提高你自己的理解,这就是我在这里的原因:-)。除此之外,我一直推荐优秀资源fsharpforfunandprofit.com,里面有各种精彩的解释。 使用 VS(或者可能是其他 IDE)可以很容易地看到发生了什么,通过将鼠标悬停在事物上来查看它们的隐含类型。否则交互窗口会立即报告类型。 @MarkPattison 真的,要是我家里的 Linux PC 上有 VS 就好了 :-) 在 Linux 上,试试 Visual Studio Code + Ionide 插件 for F#

以上是关于F#:使用区分联合解构绑定的主要内容,如果未能解决你的问题,请参考以下文章

空F#区分联合案例的C#类型

展开 F# 单例区分联合元组类型

F#如何在递归可区分联合中指定类型限制

为啥 F# 可区分联合无法使其 TypeConverter 受到 JSON.NET 的尊重,而其他类型却可以?

同一个列表中非常相似的类型(继承 vs 区分联合 vs 泛型?)

在 TypeScript 中重载联合类型