差异联合类型和区分联合打字稿/ F#
Posted
技术标签:
【中文标题】差异联合类型和区分联合打字稿/ F#【英文标题】:Difference union types and discriminated unions typescript/F# 【发布时间】:2020-08-22 01:50:48 【问题描述】:所以我正在阅读关于联合类型的 Typescript 官方文档,我认为它与 F# 中的“可区分联合”相同(假设它们具有不同的语法但相同的概念),因为我有 F# 背景和鉴于两者都得到了微软的支持。但是查看文档,F# 并没有真正区分“联合类型”和“有区别的联合”:https://fsharpforfunandprofit.com/posts/discriminated-unions/
但是,Typescript 确实区分了这两个概念:
联合类型:https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types
歧视工会:https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions
所以我想知道这些概念本身是否真的有区别,或者只是一些依赖于语言的概念?
目前我的理解是,F# 中的联合类型也是可区分联合,因为您可以使用匹配表达式和解构来区分联合类型。
但是,您不能使用 Typescript 进行区分,因为该语言没有提供特定的表达式来做到这一点,因此您需要通过一个值来区分,所有联合类型都具有判别式。这是正确的吗?
【问题讨论】:
是的,TS 中的判别式只是您选择的任意对象属性。对于有区别的或标记的联合,您不需要这个,因为类型本身携带了这些信息。由于在编译期间不会删除标记,因此您可以在运行时对其进行模式匹配。 【参考方案1】:类型联合(A | B)
中的操作数都是类型,而可区分联合type U = A | B
中的情况都是U
类型的构造函数,而不是类型本身。 U
类型的值在运行时被标记,因此您可以区分可能的情况。
一个结果是,有区别的联合可以以联合类型可能不会嵌套的方式嵌套。联合类型系统中某些类型A
的可选值可能表示为
type A? = (A | null)
其中null
是null
值的单例类型。
对于有区别的联合,它通常表示为
type a' option = Some of 'a | None
这个公式的价值
let o: int option option = Some None
不能用联合类型表示,因为(A?)?
== (A | null) | null
== A | null
== A?
【讨论】:
当然可以extend untagged unions 我真的很喜欢你基于类型构造器思想的解释,这更有意义。但是为什么嵌套联合不能与联合类型一起使用,谁来“减少”你展示的类型?以及为什么有区别的联合确实适用于嵌套类型?【参考方案2】:主要区别在于,Typescript Union Type 实际上是 F# Discriminator Union 的超集。
TypeScript 联合类型 = 未标记 联合类型。 F# 可区分联合 = 标记联合类型。
换句话说,可以在 F# 中建模的每个可区分联合都可以在 Typescript 联合类型中同构地建模,但反之则不然。
例如,F#中的以下可区分联合:
type a' Option = Some of 'a | None
可以在 Typescript 中同构建模为:
type Option<T> = tag: 'Some', value: T | tag: 'None'
但是,以下 Typescript 联合类型无法在 F# 中进行同构建模:
type UserInput = number | string
这里的主要区别是 TypeScript 联合类型不需要标记,而 F# 联合类型必须标记。
因此,我们可以看到 TypeScript 实际上比 F# 更灵活,但这并不是没有代价的,未标记的联合实际上是有漏洞的,这意味着有些类型的联合会导致 TypeScript 无法进行类型检查。
就像非类型 lambda 演算是类型化 lambda 演算的超集,但类型 lambda 演算更容易证明正确。
【讨论】:
所以联合类型基本上允许对可能的多种类型使用类型别名,这是有区别的联合不能做到的,它们只能用于一种类型。正如@Lee 在他的回答中提到的那样,对于有区别的联合,我们需要类型构造函数,它们是“案例”或标记标签。定义一个有区别的联合就是为一个类型指定不同的类型构造函数。而对于联合类型,我们可以定义其他类型的类型别名。以上是关于差异联合类型和区分联合打字稿/ F#的主要内容,如果未能解决你的问题,请参考以下文章