Ocaml中的打印类型

Ocaml中的打印类型,ocaml,Ocaml,我在OCaml中有一些非常简单的逻辑: let load filename = let file = get_file filename in let len = String.length file in Printf.printf "%a\n" file () get_文件是我编写的一个函数。正如您从这段代码中看到的,我想打印文件的内容,以了解它返回的内容。我之所以使用%a,是因为其中一个OCaml教程说,对于这种情况,您应该这样做。当我说这类事情时,我指的是一个频道,为此

我在OCaml中有一些非常简单的逻辑:

let load filename =
  let file = get_file filename in
  let len = String.length file in
  Printf.printf "%a\n" file
  ()
get_文件是我编写的一个函数。正如您从这段代码中看到的,我想打印文件的内容,以了解它返回的内容。我之所以使用%a,是因为其中一个OCaml教程说,对于这种情况,您应该这样做。当我说这类事情时,我指的是一个频道,为此,我将展示我的get_file函数的样子:

let get_file filename =
  let channel = open_in_bin filename in
  let length = in_channel_length channel in
  let file = really_input_string channel length in
  close_in channel;
  file
好的,参考load方法中的代码,我得到以下错误:

6 |   Printf.printf "%a\n" file
                           ^^^^
Error: This expression has type string but an expression was expected of type
         out_channel -> 'a -> unit
所以我想好了,这是一个类型字符串-因为这是消息告诉我的-所以我应该在printf中这样做。因此,我将printf更改为:

Printf.printf "%s\n" file
Printf.printf "%d\n" len
但现在的错误是:

6 |   Printf.printf "%s\n" file
                    ^^^^^^
Error: This expression has type
         ('a -> 'b, out_channel, unit, unit, unit, 'a -> 'b)
         CamlinternalFormatBasics.fmt
       but an expression was expected of type
         ('a -> 'b, out_channel, unit, unit, unit, unit)
         CamlinternalFormatBasics.fmt
       Type 'a -> 'b is not compatible with type unit 
考虑到我最初使用%a时使用的错误消息,我不知道您应该如何利用该迟钝的错误消息

然后我想也许这个文件是错误的,因为它是这个频道的东西,也许我遗漏了什么。所以我试着打印出len变量,它应该是一个正整数。我将printf更改为:

Printf.printf "%s\n" file
Printf.printf "%d\n" len
我收到另一条对我没用的错误消息:

6 |   Printf.printf "%d\n" len
                    ^^^^^^
Error: This expression has type
         ('a -> 'b, out_channel, unit, unit, unit, 'a -> 'b)
         CamlinternalFormatBasics.fmt
       but an expression was expected of type
         ('a -> 'b, out_channel, unit, unit, unit, unit)
         CamlinternalFormatBasics.fmt
       Type 'a -> 'b is not compatible with type unit 
我尝试将len的printf切换到%a,只是为了查看它报告了什么,我得到了以下结果:

6 |   Printf.printf "%a\n" len
                           ^^^
Error: This expression has type int but an expression was expected of type
         out_channel -> 'a -> unit
是的,它有一个int类型。这是我最初试图打印的!所以这是第一种情况的镜像。一条错误消息告诉我变量是一种特定类型。然后我试着打印那个特定的类型,我得到了更长的,但对我来说没什么帮助的错误消息


我找不到一个像样的OCaml教程,它只是带你通过这个简单的例子,使用诊断打印语句来确定语言在做什么,因此在这里发布来找出我做错了什么。

错误消息的问题是Printf函数族非常灵活,当发送到函数的参数数量超出预期时,会转换为非常复杂的错误消息

在你的第一个案例中

Printf.printf "%a\n" file ()
Printf收到正确数量的参数,因为说明符%a需要两个参数:自定义打印机和需要打印的数据。因此,您在文件上得到了一个类型错误,因为文件不是打印函数

但在第二种情况下,

Printf.printf "%s\n" file ()
争论的数量是错误的

然后,类型检查器尝试将预期的参数数量与实际的参数数量进行协调。在探索中,推断出如果

Printf.printf "%s\n" file
返回一个函数。特别是,

Printf.kprintf (fun _ () -> ()) "%s\n" file
好的。 这就是错误消息试图说的。如果我们关注最后一种类型 参数

Error: This expression has type
         (..., 'a -> 'b) fmt
       but an expression was expected of type
         (..., unit) fmt
       Type 'a -> 'b is not compatible with type unit
第一行告诉我们,与格式参数相比,参数的数量要求我们在打印结束时返回“a->”b类型的函数。 但是,最后一行告诉我们Printf.Printf函数只能在打印结束时返回一个unit类型的值。
由于单元和“a->”b不是同一类型,因此这是一个错误

看起来Printf.Printf行中缺少分号,因此该参数正在传递到Printf.Printf。这是故意的吗?看起来像个虫子。哦,哦,那太尴尬了。看起来是这样的。或者,更确切地说,这有点尴尬。我仍然不清楚何时使用分号,何时不必使用分号,我也不知道为什么每次的错误消息都会如此不同,因为显然是分号。但我猜你的意思表明:这个问题正在被传递。我认为你应该治疗expr;等同于let=expr in;i、 当表达式的计算结果为unit时,可以使用分号。