假设我有两种类型,Vector2D
和 Vector3D
并且它们被标记(这是正确的术语,对吧?),并且我想编写一个仅运行的函数在 Vector2D
上(或者这里的 vector(two)
更正确吗?),如下所示:
type two;
type three;
type vector('a) =
| Vector2D(float, float): vector(two)
| Vector3D(float, float, float): vector(three);
let first = (a: vector(two)) => {
switch(a) {
| (x, y) => x +. y
}
}
let second = (Vector2D(x, y)) => {
x +. y
}
let third = ((x, y): vector(two)) => {
x +.y
}
first
和 second
函数禁止传递 Vector3D
,正如我想要的那样,但它们发出警告“此模式匹配并不详尽” ”。
对于first
,我想知道为什么这并不详尽,我是否没有将可能的选项限制为Vector2D
?对于 second
我猜原因与 first
相同,但是如何用这种语法解决问题呢?
至于third
,这个无法编译,因为“此模式匹配 ('a, 'b) 但需要向量(two)”。为什么编译器需要这里有任何元组?函数参数中不能使用解构吗?
编辑:
事实证明,有一个更简单的问题来演示我想要的内容
type state = Solid | Liquid
let splash = (object) => {
switch(object) {
| Liquid => "splashing sounds. I guess."
| Solid => "" // this should not even be possible in the context of this function, and I want to compiler to enforce this
}
最佳答案
关于 GADT 部分,这里的问题是您正在使用bucklescript 及其古老的 4.02.3 编译器版本。 例如,以下代码在 OCaml ≥ 4.03 中运行得非常好:
type two = Two ;
type three = Three ;
/* Never define abstract types when you want to use them as type level tags,
your code will only works inside the module defining them, and then
fail due to injectivity problems.
*/
type vector('a) =
| Vector2D(float, float): vector(two)
| Vector3D(float, float, float): vector(three);
let sum_2 = (Vector2D(x,y)) => x +. y
let sum_3 = (Vector3D(x,y,z)) => x +. y +. z
let sum_any = (type a, x: vector(a) ) => switch (x) {
| Vector2D(x,y) => x +. y;
| Vector3D(x,y,z) => x +. y +. z
}
但它会在 4.02.3 上失败,并出现详尽性警告(应将其视为错误),因为仅在 4.03 中添加了针对带有反驳子句的 GADT 的详尽性检查。
关于pattern-matching - 如何将参数限制为变体类型的仅一种变体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58721045/