尝试在产品类型上编写函数时键入冲突

时间:2013-04-02 13:26:33

标签: sml ml

我在标准ML中有以下代码:

datatype a = a;
val x = a;
val y:a = a;
val z = a;

fun fa a = a;

fun not' x = case x of
    true => false
  | false => true;

fun fst (a,b) = a;
fun snd (a,b) = b;

我对sum类型(not')的函数运行正常,但是当我尝试在产品类型(fst)上使用我的函数时,它会给我这个错误:

- fst (1,2);
! Toplevel input:
! fst (1,2);
!      ^
! Type clash: expression of type
!   int
! cannot have type
!   a
-  

为什么?

1 个答案:

答案 0 :(得分:1)

您需要更多地了解变量名称和范围。

发生的事情是您声明了一个带有类型构造函数a和值构造函数a的数据类型。然后,您迟迟在afst函数中使用snd作为参数,这意味着您正在匹配数据类型的值构造函数a。可能不是你想要的。

快速修复只是更改两个函数中使用的变量名

fun fst (x, y) = x;
fun snd (x, y) = y;

- fst(1,2);
val it = 1 : int

通常从类型中可以很容易地看出问题,但是当你选择了一个相当不幸的名字时,你的函数的原始类型是

val fst = fn : a * 'a -> a
val snd = fn : a * 'a -> 'a

但是当函数被修复为不引用数据类型a时,它们将具有'a而不是

val fst = fn : 'a * 'b -> 'a
val snd = fn : 'a * 'b -> 'b

通常认为从值构造函数的大写字母和类型构造函数的所有小写字母开始都是好的样式。一个例子是选项数据类型,但它使用值构造函数的所有大写字母(其他一些语言甚至强制执行此操作)

datatype 'a option = NONE 
                   | SOME of 'a

如果我们将用于类型和值的名称分开,并将其称为“a”以外的其他名称,那么整个思考可能会更有意义,因为它也被用作“第一”多态类型变量的一部分(即,大多数口译员以'a)开头。

datatype foo = Bar;
val x = Bar;
val y:foo = Bar;
val z = Bar;

fun fa Bar = Bar;