在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中是否可能与此类似?
答案 0 :(得分:4)
我不知道OCaml中有与TypeError
等效的内容,并且快速搜索并没有发现明显的问题。但是我可以想到两种实现您想要的效果的方法:对DSL实施类型约束。
您可能要检查嵌入"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 *)