约束多态类型
我的范围类型定义为:
type 'a range = Full | Range of ('a * 'a)
但是,我想将 'a 限制为整数、浮点数或字符,而 'a 没有其他有效类型。
Range(0,10) (* valid *)
Range(0.0, 10.0) (* valid *)
Range('a', 'z') (* valid *)
Range("string1", "string2") (* other types like this shouldn't type check *)
我认为我可以将类型定义更改为:
type sequential = S_int of int | S_float of float | S_char of char ;;
type range = Full | Range of (sequential * sequential);;
但是,这将允许类似:
Range(S_int(0), S_float(10.0));; (* problem: mixes int and float *)
...但我希望 Range 的两个组件具有相同的类型。
我想另一种方法是创建一个 int_range 类型、一个 float_range 类型和一个 char_range 类型,但我想知道是否还有其他方法?
I've got a range type defined as:
type 'a range = Full | Range of ('a * 'a)
However, I'd like to constrain 'a to be integer or float or char, with no other valid types for 'a.
Range(0,10) (* valid *)
Range(0.0, 10.0) (* valid *)
Range('a', 'z') (* valid *)
Range("string1", "string2") (* other types like this shouldn't type check *)
I figured that I could change my type definitions to:
type sequential = S_int of int | S_float of float | S_char of char ;;
type range = Full | Range of (sequential * sequential);;
However, this would then allow something like:
Range(S_int(0), S_float(10.0));; (* problem: mixes int and float *)
...but I want both components of Range to be the same type.
I suppose that another approach would be to create an int_range type, a float_range type, and a char_range type but I'm wondering if there's another way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
另一种方法是将类型声明为私有并公开仅使用您想要的类型构造它的函数,例如:
Another approach is to declare type private and expose functions constructing it only with the types you want, e.g. :
从 Haskell 的做法中得到提示(声明一个类型类
(Sequential a) => Range a
),您可以使用函子:并使用它来提供所需的模块:
缺点是您失去
范围
的参数性;好处是,您在range
上的参数函数现在位于模块Range
中,正如它们可能应该的那样。一般来说,
Range
会对Sequential
提出许多要求,以补偿参数性的损失。这些要求可以在函子参数的签名中清楚地指定:要在特定类型上实例化
Range
,您现在需要提供一个正确参数化它的结构:然后您可以像这样使用它
:(使用新语法进行分隔重载)。如果您需要将
Range
的实现隐藏在签名后面,则可能需要重新导出SEQUENTIAL
的类型,就像标准库中的数据结构一样do:这为您提供了可以进行模式匹配但不能构造的封装和半透明类型。在签名中声明私有类型的另一种方法是使用视图类型或解构函数。
Taking a hint from what Haskell would do (declare a type class
(Sequential a) => Range a
) you could use a functor:and use it to provide the required modules:
The downside is that you lose parametricity on
range
; the upside is that your parametric functions onrange
s now live inside the moduleRange
, as they probably should.In general,
Range
s will make a number of demands ofSequential
s in order to compensate for the loss of parametricity. These requirements can be cleanly specified in the signature of the functor parameter:To instantiate the
Range
at a specific type you now need to provide a structure that properly parameterizes it:Then you can use it like this:
(using the new syntax for delimited overloading). If you need to hide the implementation of
Range
s behind a signature, you might need to re-export the type ofSEQUENTIAL
s, much as the data structures in the standard library do:This gives you encapsulation and translucent types that can be pattern-matched but not constructed. An alternative to declaring
private
types in the signature is to use a view type or a destructuring function.OMG 模块好复杂啊!
天啊,我们需要添加另一个:
OMG modules are so complicated!
Oh dang, we need to add another one: