Types OCaml详细类型错误

Types OCaml详细类型错误,types,compiler-errors,ocaml,Types,Compiler Errors,Ocaml,是否可以让OCaml显示有关类型错误的更多详细信息。比如说 Error: This expression has type AAAAA but an expression was expected of type BBBBB 有时,我会浪费大量精力试图找出哪些晦涩的语句期望BBBBB会导致这样的错误。如果它能显示有问题的行,那就太好了。适合我: $ cat miaou.ml let a = 1 == 'a';; $ ocamlc miaou.ml File "miaou.ml

是否可以让OCaml显示有关类型错误的更多详细信息。比如说

Error: This expression has type AAAAA
       but an expression was expected of type BBBBB
有时,我会浪费大量精力试图找出哪些晦涩的语句期望BBBBB会导致这样的错误。如果它能显示有问题的行,那就太好了。

适合我:

$ cat miaou.ml 
let a = 1 == 'a';;
$ ocamlc miaou.ml 
File "miaou.ml", line 1, characters 13-16:
Error: This expression has type char but an expression was expected of type
         int

可能您使用的是行号没有意义的交互式shell。

是的,这是可能的。但是您需要与编译器进行一些协作,然后它将以更友好的错误响应您。因此,您的问题的答案是-使用类型注释。当您注释表达式时,您可以向编译器提供有关您意图的更多信息。然后,编译器可以向您显示更接近实际故障点的错误

例如:

您有一个正确的函数,该函数进行类型检查,但包含一个bug:

let run sum n lst = 
    List.fold ~init:(sum,n)
              ~f:(fun (s,n) x -> s + x, n + 1)
稍后,您尝试使用它时,它会在您身上溢出一个奇怪的错误:

let average lst =
    let (sum,n) = run 0 0 lst in
    sum / n;;
    Characters 36-47:
      let (sum,n) = run 0 0 lst in
                    ^^^^^^^^^^^
Error: This expression has type int Core_kernel.Std.List.t -> int * int
       but an expression was expected of type 'a * 'b
所以,你有麻烦了,你需要调查这个问题。您开始添加注释,本质上是向编译器解释您的意图。一段时间后,您将返回到
run
的定义并添加注释:

let run sum n lst : int * int = 
    List.fold ~init:(sum,n)
              ~f:(fun (s,n) x -> s + x, n + 1)
并找出实际错误在这个函数中

所以,这里有一些规则,可以帮助您从编译器中获得更多信息性错误:

  • 注释顶级表达式(如果不想指定它们,您可以省略一些细节,以便代码仍然可读。例如,您可以编写
    (非常复杂的类型)列表
    ,而不是
    'a列表
    ,或
    ('a,'b类型)列表
    。注意,这里的
    'a
    'b
    不代表多态类型变量,这只是对编译器说的一种方式:“哦,我真的不知道,或者不在乎它们代表什么,只要随意用你想要的任何东西填充它就行了”,或者换句话说,你没有限制这种类型的类型检查器)

  • 始终注释通配符。如果你有这样的东西:

    让u=List.fold

  • 然后确保这个通配符实际上代表了您对它们的想法:

    let _ : int option = List.fold ...
    
  • 使用
    merlin
    。它将允许您在创建错误的那一刻捕获错误,而不是几个小时之后
    最后一句话:OCaml typechecker只是一个约束解算器,如果你给它一组详细的约束,它会给你一个详细的答案。否则,对于错误的输入,它将给您一个错误的输出。

    Arthur Charguéraud为OCaml编译器编写了一个补丁,提供了更容易理解的错误消息。2014年ML车间的中对其进行了描述,相应代码为。要引用演示文稿中提供的示例,请键入

    let rev_filter f l =
      List.fold_left (fun x acc -> if f x then x::acc else acc) [] [1; 2; 3]
    
    而不是经典的错误消息

    Error: This expression has type 'a list
           but an expression was expected of type 'a.
           The type variable 'a occurs inside 'a list
    
    诚然,这并不是很有帮助,你有一个新的:

    Error: The function `List.fold_left' expects 3 arguments of types
           ['a -> 'b -> 'a] and ['a] and ['b list],
           but it is given 3 arguments of types ['c -> 'c list -> 'c list]
           and ['d list] and [int list].
    

    这可以让你比较预期的和实际的参数类型,并希望理解你必须在
    fun x acc->

    中交换
    x
    acc
    ,而没有一点代码显示你认为编译器做得不好的地方,这只是一个咆哮,不是一个问题,utop甚至强调了错误发生的地方:-)是的,您的方法是最佳实践,可以解决我的问题,尽管我的印象是编译器必须有一些关于类型如何冲突的深入信息,为什么它不能只显示它们呢。在我的特殊情况下,它通常发生在重构函数时。如果一个函数从多个地方调用,并且还作为参数传递给其他函数。我不能只搜索函数名,因为它可以重命名为其他函数中的其他名称。编译器有一组约束,比如
    expr
    应该有类型
    x
    ,在类型检查的过程中,他向集合中添加新的约束,直到它遇到两个相互矛盾的约束。这是一个类型错误,编译器只输出它们。编译器甚至不知道第一个约束是什么,以及后来添加了什么。它可能会暴露其他约束,但它只适用于非常小的程序。在很大程度上,这将造成更多的混乱。这将是有用的indeed@nlucaroni扰流板
    >
    是否故意存在:因为问题是关于理解错误消息,我认为最好让读者自己搜索问题所在,以及第二条消息是否比第一条消息更有用。为什么此修补程序从未合并到核心中-(现在已经过时了,不能使用了。