等同于OCaml中的haskell TypeError

时间:2018-12-28 17:08:41

标签: haskell types ocaml

在Haskell中,可以在类型推断期间引发类型错误,以在DSL上施加类型约束。

class ValidHarmInterval (i :: IntervalType)
instance TypeError (Text "Minor seconds forbidden.")
=> ValidHarmInterval (Interval Min Second)
instance TypeError (Text "Major sevenths forbidden.")
=> ValidHarmInterval (Interval Maj Seventh)
instance {-# OVERLAPPABLE #-} ValidHarmInterval i

在OCaml中是否可能与此类似?

1 个答案:

答案 0 :(得分:4)

我不知道OCaml中有与TypeError等效的内容,并且快速搜索并没有发现明显的问题。但是我可以想到两种实现您想要的效果的方法:对DSL实施类型约束。

键入最终(无标签-最终)样式的EDSL

您可能要检查嵌入"typed final" style的Oleg所描述的DSL。似乎正是您想要的属性:

  

如果还键入要嵌入的DSL,则键入的最终方法特别有吸引力。然后,我们不仅可以用宿主语言表示术语,而且可以表示DSL的类型系统(类型派生)。只能嵌入类型良好的DSL术语。

教程Modular, composable, typed optimizations in the tagless-final style提供了有关使用OCaml编写这种样式的EDSL的分步说明。

多态类型变体

OCaml提供了另一种更轻便的方法(但行为可能不太好吗?)来对这种子类型关系施加类型约束:polymorphic variants

我们可以使用多态变体来定义区间类型:

type 'a interval =
  [< `Unison
  | `Second
  | `Third
  | `Fourth
  | `Fifth
  | `Sixth
  | `Seventh
  | `Octave
  ] as 'a

其中<表示变体的任何子集都可以构造类型为'a interval的值(暂时忽略类型变量)。

因此,我们可以编写一个将_ interval带到string的标准函数,并按预期方式将check输入为_ interval -> string

let interval_to_string : _ interval -> string = function
  | `Unison  -> "Unison"
  | `Second  -> "Second"
  | `Third   -> "Third"
  | `Fourth  -> "Fourth"
  | `Fifth   -> "Fifth"
  | `Sixth   -> "Sixth"
  | `Seventh -> "Seventh"
  | `Octave  -> "Octave"

但是我们也可以定义一个仅包含类型_ interval一些值的函数:

let even_interval_to_int : _ interval -> int = function
  | `Second -> 2
  | `Fourth -> 4
  | `Sixth  -> 6
  | `Octave -> 8

interval_to_string一样,even_interval_to_int也是类型_ interval的值的函数,但是如果将其应用于不受支持的时间间隔,则类型检查将失败:

let invalid_int_of_even_interval = even_interval_to_int `Third
(* Error: This expression has type [> `Third ]
 *        but an expression was expected of type
 *          [< `Fourth | `Octave | `Second | `Sixth ]
 *        The second variant type does not allow tag(s) `Third *)

这是因为[< Fourth |Octave | Second |Sixth ]Fourth |的子类型。

转到您的示例(请原谅我对音乐理论的无知),我们可以将次谐波和次谐波间隔编码为Second |的相交但不相同的子集:

_ interval

然后约束我们的_ interval,以便type major_harmonic_interval = [ `Unison | `Second | `Third | `Fourth | `Fifth | `Sixth (* No Seventh *) | `Octave ] type minor_harmonic_interval = [ `Unison (* No Second*) | `Third | `Fourth | `Fifth | `Sixth | `Seventh | `Octave ] type harmonic_interval构造函数只能构造具有适当类型变体的值:

Major

这将使我们构建所需的谐波间隔:

Minor

但是强迫类型系统禁止我们没有的任何谐波间隔

type harmonic_interval =
  | Major of major_harmonic_interval
  | Minor of minor_harmonic_interval

同时,我们仍然可以使用我们编写的对let major_second = Major `Second 类型的值进行操作的函数:

let minor_second = Minor `Second
(* Error: This expression has type [> `Second ]
 *        but an expression was expected of type minor_harmonic_interval
 *        The second variant type does not allow tag(s) `Second *)