在Standard ML中定义几种数据类型:
datatype color = orange | navy | teal | silver | hsl of real * real * real;
datatype direction = east | north | west | south;
然后我定义了一个使用上述数据类型的值:
type Cursor = int * int * color * direction;
val cursor : Cursor = (0, 0, orange, east);
它是一个“光标”,具有位置,绘图颜色和方向。 我想要的是它的属性最初是未定义的。我可以为每个color
和direction
数据类型添加构造函数(我将如何使用int
位置值?),如下所示:
datatype color = orange | teal | silver | hsl of real * real * real | undefined;
datatype direction = east | north | west | south | undefined;
val cursor : Cursor = (0, 0, undefined, undefined);
我想这样做没有必须为每种数据类型显式定义一个额外的undefined
构造函数。你能想到一个好的,干净的解决方案吗?某些形式的泛型,我可以简单地使用“未定义值”的形式,无论类型如何。类似于Javas Nullable
,粗略地说。
我的动机是我的光标属性最初是未定义的。
答案 0 :(得分:3)
为此,人们通常使用option
类型。
您生成的机器人类型将是:
type Robot = (int * int * color * direction) option;
或组件明智。这也与简单地自己创建具有两个构造函数的数据类型相同(一个表示未定义的值,一个表示初始化的值),但option
是执行此操作的标准方法,这也鼓励了monadic编程风格
这会让你输入安全性,因为每当你破坏类型的值时都需要匹配两个构造函数。
答案 1 :(得分:3)
没有语法糖能够引用具有相同名称的不同构造函数。 (换句话说:标准ML不允许自定义重载。)相反,首先声明的构造函数会被另一种类型的类似拼写构造函数覆盖。
Haskell有一个名为undefined
的值,在评估时会抛出异常。因此,此值的类型不受任何特定类型的约束,并且是多态的,这意味着undefined可以在任何地方使用。
标准ML不能将此值定义为抛出异常的别名,因为它是严格评估的。这意味着声明了val undefined = raise Undefined
时刻,抛出异常。但是可以在尚未编写的程序的某些部分中使用raise Undefined
,只要不立即进行评估即可。
代数类型的一个非常重要的优势是,除非您明确形成支持它的类型(例如,使用'a option
),否则您不会意外地具有类似null的值。