Types 如何将OCaml整数类型约束为整数范围?

Types 如何将OCaml整数类型约束为整数范围?,types,ocaml,Types,Ocaml,在阅读真实世界的OCaml书籍时,我遇到了以下类型声明(第6章:变体): 我认为RGB和灰色变体可以进一步限制。例如,RGB元组中的每个int只能具有0-5的值 在Erlang中,我会这样做: -type rgbint() :: 0 | 1 | 2 | 3 | 4 | 5. -type rgb() :: {rgb_int(), rgb_int(), rgb_int(). 然而,当我在OCaml(utop)中尝试此功能时,它抱怨: # type rgbint = 0 | 1 | 2 | 3 |

在阅读真实世界的OCaml书籍时,我遇到了以下类型声明(第6章:变体):

我认为RGB和灰色变体可以进一步限制。例如,RGB元组中的每个int只能具有0-5的值

在Erlang中,我会这样做:

-type rgbint() :: 0 | 1 | 2 | 3 | 4 | 5.
-type rgb() :: {rgb_int(), rgb_int(), rgb_int().
然而,当我在OCaml(utop)中尝试此功能时,它抱怨:

# type rgbint = 0 | 1 | 2 | 3 | 4 | 5 ;;

Error: Parse error: [type_kind] expected after "=" (in [opt_eq_pluseq_ctyp]) 
问题:

  • 在OCaml中,是否不允许在类型定义的RHS上使用文本
  • 在OCaml中,如何执行上面的Erlang rgbint()定义
致以感谢和良好的祝愿


Ivan

通过某个基本类型的值列表来定义类型是有意义的,但是OCaml没有这样的类型。它有一组基本类型,如
int
char
。您可以定义自己的新基元类型,其值为文本,如
Yes
No
。(当您定义这样一个文字时,它看起来像一个大写的标识符。)您可以将这些文字与参数化类型(如列表、数组等)相结合

如果确实希望int值限制在某个范围内,可以将其定义为模块接口隐藏的抽象类型。在该模块中,您需要定义要在有限的整数范围内支持的所有操作。(请注意,在通常的算术运算中,此类类型不是闭合的。)

您还可以定义:

type rgbint = RBG0 | RGB1 | RGB2 | RGB3 | RGB4 | RGB5
实际上,这可能是您最终要做的事情,尽管当您将底层值视为数字时,这种类型会感觉很麻烦。

这是私有类型的典型用例 OCaml允许您 这使得它介于具体类型和抽象类型之间:

  • 与具体类型的值类似,私有类型的值 可以使用am匹配模式解构

  • 与抽象类型的值一样,私有类型的值 只能使用模块中的函数构造 定义此类型

例如,您的代码片段可以翻译为

module Color : sig
  type t =
  | Basic of basic_color * weight   (* basic colors, regular and bold *)
  | RGB of rgbint * rgbint * rgbint (* 6x6x6 color cube *)
  | Gray of int                     (* 24 grayscale levels *)
  and basic_color =
   | Black | Red | Green | Yellow | Blue | Magenta | Cyan | White
  and weight = Regular | Bold
  and rgbint = private int
  val rgb : int * int * int -> t
end = struct
  type t =
  | Basic of basic_color * weight
  | RGB   of rgbint * rgbint * rgbint
  | Gray  of int
  and basic_color =
   | Black | Red | Green | Yellow | Blue | Magenta | Cyan | White
  and weight = Regular | Bold
  and rgbint = int

  let rgb (r, g, b) =
    let validate x =
      if x >= 0 && x < 6 then x else invalid_arg "Color.rgb"
    in
    RGB (validate r, validate g, validate b)
end
无法从其组件中自组装
Color.RGB
值:

# Color.RGB(0,0,0);;
Characters 10-11:
  Color.RGB(0,0,0);;
            ^
Error: This expression has type int but an expression was expected of type
         Color.rgbint
可以使用类型强制将
Color.rgbint
类型的值解构为整数:

# match Color.rgb(0,0,0) with
  | Color.RGB(r,g,b) ->
    if ((r,g,b) :> int * int * int) = (0, 0, 0) then
      "Black"
    else
      "Other"
  | _ -> "Other";;      
- : string = "Black"
Yaron Minsky写了两篇关于私人类型的博文,值得一读:


在erlang中,范围检查是动态的,对吗?还可以使用多边形变体来缓解烦恼,“11”12岁,12岁以下,12岁以下,12岁以下,12岁以下,12岁以下,13岁以下,13岁以下,14岁以下,14岁以下,14岁以下,14岁以下,14岁以下,14岁以下以下以下以下,让让v w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w函数函数的功能10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10??????????| 824;->断言为false@Drup是,但是。。。是的,erlang使用动态类型,但是使用上面的类型注释,您可以在编译时键入检查代码(例如,使用dialyzer)。@Edgar谢谢,但不理解。我只是在RWO的第6章:)所以,在底部你是说,“使用运行时验证”?你指的是类型强制吗?类型强制由编译器控制,是类型安全的,并保证在运行时不会中断。类型强制是对类型解算器的提示,而不是对未定义行为的敞开大门。不,我指的是验证函数。哦,好的!:)是的,但这并不像看上去的那么糟糕,因为很清楚谁负责这个验证。如果我们序列化和反序列化数据,那么运行时验证是非可选的。使用有限枚举是可行的,但前提是枚举中的项足够小。谢谢。这正是我所担心的——而且只适用于符号类型,不适用于例如浮点范围,但我想我们正在进入依赖类型的领域。这个例子很麻烦是的:otoh我可能想用一种方法将rgb三元组“添加”在一起,以创建一个新的rgb三元组
# Color.RGB(0,0,0);;
Characters 10-11:
  Color.RGB(0,0,0);;
            ^
Error: This expression has type int but an expression was expected of type
         Color.rgbint
# match Color.rgb(0,0,0) with
  | Color.RGB(r,g,b) ->
    if ((r,g,b) :> int * int * int) = (0, 0, 0) then
      "Black"
    else
      "Other"
  | _ -> "Other";;      
- : string = "Black"