如何将参数限制为变量类型的一个变量

假设我有两种类型,Vector3DVector2D,并且它们被标记了(这是正确的术语,对吗?),我想编写一个仅在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

secondVector3D函数禁止传递first,就像我想要的那样,但是它们会发出警告“此模式匹配并不详尽”。

对于Vector2D,我想知道为什么这还不详尽,是否在这里我不将可能的选项限制为second?对于first,我想原因与third相同,但是用这种语法怎么可能解决这个问题呢?

对于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 } ,由于“此模式与('a,'b)匹配,但预期为vector(two)”,因此该代码无法编译。为什么编译器期望这里有任何元组?不能在函数参数中使用解构吗?

编辑:
事实证明,还有一个更简单的问题来证明我想要的东西

{{1}}
jahy988 回答:如何将参数限制为变量类型的一个变量

关于GADT部分,这里的问题是您正在使用扣脚本及其古老的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,z) => x +. y +. z
}

但是它会在4.02.3上失败,并带有穷举性警告(应将其视为错误),因为仅在4.03中才添加了带有引用子句的GADT的穷举性检查。

,

您可以使用polymorphic variants完成所需的操作:

type vector = [
  | `Vector2D(float,float)
  | `Vector3D(float,float)
];

let first = (a: [`Vector2D(float,float)]) => {
  switch(a) {
    | `Vector2D(x,y) => x +. y
  }
}

let second = (`Vector2D(x,y)) => {
  x +. y
}

如果您尝试将`Vector3D传递给任何一个函数,这将给您键入错误:

               ^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type [> `Vector3d(float,float) ]
       but an expression was expected of type [< `Vector2D(float,float) ]
       The second variant type does not allow tag(s) `Vector3d

首先请注意,示例中的Vector2DVector3D不是类型。它们是构造vector('a)类型的值的构造函数。正如您正确指出的那样,它们有时也称为“标签”,而该类型有时也称为“标签联合”而不是“变量”,因为值包含一个标签,该标签指定了用于构造该标签的构造器。当您使用构造函数模式进行模式匹配时,将检查标记。

您在示例中使用的不是普通变体,而是Generalized Algebraic Data Type (GADT)(在OCaml / Reason中可能更恰当地命名为“ Generalized Variant”),其原因不起作用的是,尽管GADT允许您将特定类型分配给构造函数,但反之则行不通。例如,您可以有几个指定vector(two)的构造函数。(编辑:这似乎是错误的,请参阅@octachron的答案)

示例中的firstthird函数均无法编译,编译器期望使用元组,因为您使用的是元组模式而不是构造函数模式。 (x,y)Vector2D(x,y)不同。如果是这样的话,例如,您将无法将Vector2D(float,float)Line(point,point)区分,其中包含完全不同类型的数据。

本文链接:https://www.f2er.com/3155778.html

大家都在问