首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这个Standard-ML类型错误的原因是什么?

这个Standard-ML类型错误的原因是什么?
EN

Stack Overflow用户
提问于 2009-12-06 06:34:06
回答 3查看 2.4K关注 0票数 0

我正在尝试制作这个非常简单的SML函数的尾递归版本:

代码语言:javascript
复制
fun suffixes [] = [[]]
  | suffixes (x::xs) = (x::xs) :: suffixes xs;

在此过程中,我在参数上使用了类型注释。下面的代码显示了这一点,并导致了类型错误(如下所示),而如果我只是删除类型注释,则SML会毫不费力地接受它,并为整个函数提供与上面更简单的函数相同的签名。

代码语言:javascript
复制
fun suffixes_tail xs =
    let
        fun suffixes_helper [] acc = []::acc
          | suffixes_helper (x::xs:'a list) (acc:'b list) =
                suffixes_helper xs ((x::xs)::acc)
    in
        suffixes_helper xs []
    end;

错误:

代码语言:javascript
复制
$ sml typeerror.sml 
Standard ML of New Jersey v110.71 [built: Thu Sep 17 16:48:42 2009]
[opening typeerror.sml]
val suffixes = fn : 'a list -> 'a list list
typeerror.sml:17.81-17.93 Error: operator and operand don't agree [UBOUND match]
  operator domain: 'a list * 'a list list
  operand:         'a list * 'b list
  in expression:
    (x :: xs) :: acc
typeerror.sml:16.13-17.94 Error: types of rules don't agree [UBOUND match]
  earlier rule(s): 'a list * 'Z list list -> 'Z list list
  this rule: 'a list * 'b list -> 'Y
  in rule:
    (x :: xs : 'a list,acc : 'b list) =>
      (suffixes_helper xs) ((x :: xs) :: acc)
/usr/local/smlnj-110.71/bin/sml: Fatal error -- Uncaught exception Error with 0
 raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27

给出了两个错误。后者在这里似乎不太重要,因为suffixes_helper的两个子句之间不匹配。第一个是我不明白的。我注释声明第一个参数的类型为'a:list,第二个参数的类型为'b:list。据我所知,Hindley-Milner类型的推理算法建立在一般统一的基础上,难道不能使用'b ---> 'a list来统一'b:list'a:list list

编辑:一个答案表明这可能与类型推断算法有关,该算法不允许推断类型,在某种意义上,推断类型比类型注释给出的类型更严格。我猜这样的规则只适用于参数上的注释和整个函数上的注释。我不知道这是否正确。在任何情况下,我都尝试将类型注释移到函数体中,但得到了同样的错误:

代码语言:javascript
复制
fun suffixes_helper [] acc = []::acc
    | suffixes_helper (x::xs) acc =
          suffixes_helper (xs:'a list) (((x::xs)::acc):'b list);

现在的错误是:

代码语言:javascript
复制
typeerror.sml:5.67-5.89 Error: expression doesn't match constraint [UBOUND match]
  expression: 'a list list
  constraint: 'b list
  in expression:
    (x :: xs) :: acc: 'b list
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-12-06 07:13:10

我不确定SML,但另一种函数式语言F#在这种情况下给出了警告。给出一个错误可能有点苛刻,但这是有道理的:如果程序员引入了一个额外的类型变量'b‘,并且如果'b’必须是一个列表类型,则该函数可能不像程序员预期的那样通用,这是值得报告的。

票数 1
EN

Stack Overflow用户

发布于 2009-12-08 00:22:49

这是可行的:

代码语言:javascript
复制
fun suffixes_tail xs =
    let
        fun suffixes_helper [] acc = []::acc
          | suffixes_helper (x::xs:'a list) (acc:'a list list) =
                suffixes_helper xs ((x::xs)::acc)
    in
        suffixes_helper xs []
    end

正如Joh和newacct所说,'b list太宽松了。在给出显式类型批注时

代码语言:javascript
复制
fun suffixes_helper (_ : 'a list) (_ : 'b list) = ...

它被隐式地量化为

代码语言:javascript
复制
fun suffixes_helper (_ : (All 'a).'a list) (_ : (All 'b).'b list) = ...

显然,'b = 'a list不能同时为true (All a') (All b')

在没有显式类型注释的情况下,类型推断可以做正确的事情,即统一类型。实际上,SML的类型系统非常简单(据我所知),它永远不会是不可决定的,因此显式类型注释永远不应该是必要的。你为什么要把它们放在这里?

票数 3
EN

Stack Overflow用户

发布于 2009-12-06 16:16:11

当您使用'a'b这样的类型变量时,这意味着'a'b可以独立地设置为任何值。例如,如果我决定'bint'afloat,那么它应该可以工作;但显然,这在本例中是无效的,因为事实证明'b必须为'a list

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1853686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档