我在文本文件 mpd.ml 中有一个简单的模块,其中包含变体类型:
type ack_error =
| Not_list
| Arg
| Password
| Permission
| Unknown
| No_exist
| Playlist_max
| System
| Playlist_load
| Update_already
| Player_sync
| Exist
type response = Ok | Error of (ack_error * int * string * string)
当我使用它们时:
let test_ok test_ctxt = assert_equal Mpd.Ok (Mpd.parse_response "OK\n")
即使一切正常,我也有这些警告:
ocamlfind ocamlc -o test -package oUnit,str -linkpkg -g mpd.ml test.ml
File "test.ml", line 7, characters 2-4:
Warning 40: Ok was selected from type Mpd.response.
It is not visible in the current scope, and will not
be selected if the type becomes unknown.
File "test.ml", line 8, characters 2-7:
Warning 40: Error was selected from type Mpd.response.
It is not visible in the current scope, and will not
be selected if the type becomes unknown.
这意味着什么,以及如何改进我的代码以避免这些警告消失。
**编辑**
完整代码:https://gist.github.com/cedlemo/8806f367a971bacfaa0f59b1c78a3605
答案 0 :(得分:3)
看起来你没有显示该线,这引发了警告。正如在警告中所述,Ok
构造函数位于字符2-4
之间,但代码中没有任何相似内容。
一般情况下,我建议使用IDE,如Emacs,Vim等,因为它们会直接跳转到错误源。
因为警告很常见,我仍然会解释其背后的原因。在OCaml中,构造函数和字段名称是标识符,该标识符以及任何其他标识符都具有范围,范围是模块。因此,无论何时定义变量类型,实际上都是在模块范围内定义了几个构造函数。要引用构造函数,您需要使用完全限定名称,或者确保它在范围内。如果您在模块中定义了它,那么您就可以了,否则您需要以某种方式将名称带到范围。
在以前版本的OCaml中,使用不在范围内的构造函数是错误的。只是一个常规的未绑定标识符。最后,添加了启发式,推断出构造函数来自哪个范围。但它仍然受到警告的保护,因此人们实际上是在努力不使用它。 (离题,我想知道为什么人们添加了一个功能,然后在一个警告的情况下瞬间贬低它,所以没有人会真正使用它)。
因此,要修复警告,您需要使用模块名称限定所有构造函数,或者,打开模块以将所有定义纳入范围,例如open Mpd
。
因此,代码完整代码公开了第7行,编译器确实指出了一个不合格的构造函数:
match response with
| Ok -> false
| Error ...
此处Ok
不合格,正确的方法是:
match response with
| Mpd.Ok -> false
| Mpd.Error ...
描述我特别使用的策略的一般建议是定义一个仅定义类型的模块,以便您可以相当安全地打开它。这也将解决您在.mli
中重复类型定义的问题,因为对于仅定义类型的模块而言,不能拥有.mli
文件是可以接受的。