Functional programming 是什么导致此标准ML类型错误?

Functional programming 是什么导致此标准ML类型错误?,functional-programming,type-inference,sml,hindley-milner,Functional Programming,Type Inference,Sml,Hindley Milner,我试图制作这个非常简单的SML函数的尾部递归版本: fun suffixes [] = [[]] | suffixes (x::xs) = (x::xs) :: suffixes xs; 在此过程中,我在参数上使用类型注释。下面的代码显示了这一点,并导致一个类型错误(如下所示),而如果我简单地删除类型注释,SML会毫无问题地接受它,为整个函数提供与上面更简单的函数相同的签名 fun suffixes_tail xs = let fun suffixes_helper

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

fun suffixes [] = [[]]
  | suffixes (x::xs) = (x::xs) :: suffixes xs;
在此过程中,我在参数上使用类型注释。下面的代码显示了这一点,并导致一个类型错误(如下所示),而如果我简单地删除类型注释,SML会毫无问题地接受它,为整个函数提供与上面更简单的函数相同的签名

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;
错误:

$ 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
给出了两个错误。后者在这里似乎不那么重要,后缀的两个子句之间不匹配。第一个是我不明白的。我注释说明第一个参数的类型为
'a:list
,第二个参数的类型为
'b:list
。根据我的理解,欣德利·米尔纳类型推理算法是建立在一般统一之上的,难道不应该使用
'b--->'a列表
的替代物将
'b:list
'a:list
统一起来吗

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

fun suffixes_helper [] acc = []::acc
    | suffixes_helper (x::xs) acc =
          suffixes_helper (xs:'a list) (((x::xs)::acc):'b list);
错误现在是:

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

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

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

当您使用像
'a
'b
这样的类型变量时,这意味着
'a
'b
可以单独设置为任何值。例如,如果我决定
'b
int
,而
'a
float
,它应该可以工作;但显然,在这种情况下这是无效的,因为当您使用类型变量如
'a
'b
时,
'b
必须是
'a列表
,这意味着
'a
'b
可以独立设置为任何值。例如,如果我决定
'b
int
,而
'a
float
,它应该可以工作;但显然,在这种情况下,这是无效的,因为事实证明,
'b
必须是
'a列表

这是有效的:

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列表
太松散了。当您给出显式类型注释时

fun suffixes_helper (_ : 'a list) (_ : 'b list) = ...
它隐式地量化为

fun suffixes_helper (_ : (All 'a).'a list) (_ : (All 'b).'b list) = ...
显然,一个列表不可能同时为真

如果没有显式的类型注释,类型推断可以做正确的事情,即统一类型。事实上,SML的类型系统非常简单(据我所知),它从来都不是不可判定的,所以显式类型注释应该是不必要的。为什么要把它们放在这里?

这样做:

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列表
太松散了。当您给出显式类型注释时

fun suffixes_helper (_ : 'a list) (_ : 'b list) = ...
它隐式地量化为

fun suffixes_helper (_ : (All 'a).'a list) (_ : (All 'b).'b list) = ...
显然,一个列表不可能同时为真


如果没有显式的类型注释,类型推断可以做正确的事情,即统一类型。事实上,SML的类型系统非常简单(据我所知),它从来都不是不可判定的,所以显式类型注释应该是不必要的。为什么要将它们放在这里?

谢谢,这是我没有考虑到的:当参数中给出类型注释时,可能会实现类型推断以禁止比给定参数更严格的推断类型。但是,如果将类型注释放在函数体中,则会出现同样的错误。我将编辑我的问题来说明这一点。您仍在注释一个比推断类型严格的类型谢谢,这是我没有考虑到的:当在参数中给出类型注释时,可能会实现类型推断以禁止比给定参数更严格的推断类型。但是,如果将类型注释放在函数体中,则会出现同样的错误。我将编辑我的问题来说明这一点。你仍然在注释一个没有推断类型严格的类型谢谢,三个答案基本上都列出了相同的原因,我接受这一解释。我最初的理解(因此对SML的行为感到惊讶)是类型注释在与任何推断类型同等的基础上添加了类型信息,因此它们可以统一为“向上”(更一般)和“向下”(更具体)。为了回答您的问题,我首先需要类型注释:虽然我也理解SML从不需要类型注释,但它们可能会增加可读性,并且(在我的例子中更合适)它们可能有助于缩小编译错误。谢谢,三个答案基本上都列出了相同的原因,我接受这一解释。我最初的理解(因此对SML的行为感到惊讶)是,类型注释在与任何推断类型同等的基础上添加了类型信息,因此它们可以同时统一