ML编译代码报错求助:raise参数类型不匹配异常问题
解析ML代码中的「tycon mismatch」异常错误
首先先还原你的问题场景:
报错信息:
7.18-7.22 Error: argument of raise is not an exception [tycon mismatch] raised: ?.R1 in expression: raise (E y) val it = () : unit
对应的代码:
exception E of real; fun g (y)= raise E(y); fun f(z)= let datatype R1=E of int; fun x(y)= raise E(y); in z(3); x(3) end;
错误原因拆解
这个问题的核心是命名屏蔽+类型构造器不匹配:
- 你在全局作用域定义了一个异常
exception E of real,它的类型是real -> exn(接收real返回异常类型)。 - 但在
f函数的let局部块里,你又定义了一个数据类型datatype R1=E of int——这里的E是R1类型的构造器,类型是int -> R1,和全局异常完全不是一回事。 - SML的规则是:局部定义的同名标识符会覆盖外部的同名定义,所以
x函数里的E(y),调用的是局部R1的构造器,返回的是R1类型的值,而不是异常类型exn。 raise关键字要求参数必须是exn类型的异常,现在传入的是R1类型的值,自然就触发了「tycon mismatch(类型构造器不匹配)」的错误。
两种解决方法
根据你的实际需求,有两种修复方案:
方案1:想在x中抛出全局的E异常
只需要修改局部数据构造器的名称,避免和全局异常重名即可:
exception E of real; fun g (y)= raise E(y); fun f(z)= let datatype R1=MyE of int; // 把局部构造器改名,避开全局的E fun x(y)= raise E(y); // 这里的E自动指向全局异常 in z(3); x(3) end;
方案2:想让局部的E成为一个异常
如果你本来就想在let里定义一个局部异常,那应该把datatype改成exception,而不是定义数据类型:
exception E of real; fun g (y)= raise E(y); fun f(z)= let exception E of int; // 定义局部异常,覆盖全局的E fun x(y)= raise E(y); in z(3); x(3) end;
这样局部的E是int -> exn类型的异常,符合raise的参数要求,编译器就不会报错了。
小提醒
SML里异常(exn类型)和数据构造器属于完全不同的类型体系,千万不能混用;另外写代码时要注意局部和全局的命名冲突,避免这种容易踩坑的屏蔽问题。
内容的提问来源于stack exchange,提问作者Sara
相关产品推荐
相关产品推荐

