Ocaml:在简单模块中使用变体类型的标签时发出警告40

时间:2016-09-12 13:06:17

标签: ocaml

我在文本文件 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

1 个答案:

答案 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文件是可以接受的。