2012-04-03 81 views
10

我是OCaml模块的新手,我没有设法使用我自己的模块,但没有将“include”和“open”结合在一起。 我试图把签名放在单独的.mli文件中,但没有成功。OCaml模块:包含AND open?

在下面,我表示最低(不)工作的例子,我试图与

ocamlc -o main Robot.ml main.ml 

编译什么我需要做的,只需要使用“打开”,或者只有“包括“,但不是他们两个?


文件 “Robot.ml”:

module type RobotSignature = 
sig 
    val top: unit -> unit 
end 

module Robot = 
struct 
    let top() = 
     begin 
     Printf.printf "top\n" 
     end 
    (* Should not be visible from the 'main' *) 
    let dummy() = 
     begin 
     Printf.printf "dummy\n" 
     end 
end 

文件 “main.ml”(不工作):

open Robot;; 

top(); 

文件 “main.ml”(工作):

include Robot;; 
open Robot;; 

top(); 
+0

我想你有问题的答案。您可能还想阅读[编译单元](http://caml.inria.fr/pub/docs/manual-ocaml/manual020.html)。但是,一旦你明白了'open'的作用,不要使用它,它会让你更难理解你的代码。 – 2012-04-03 17:57:41

+0

那么我通常会同意,但在这种情况下,目标是提供一个简单的“机器人库”,教给初学者基本的编程(特别是,但不限于OCaml)。所以我宁愿尽可能避免使用Robot.top()语法。 – 2012-04-03 18:09:22

+0

嗯,我认为这实际上会让初学者更加不可理解地渲染他们正在采取行动的对象。无论如何,您可能还想查看[open](http://caml.inria.fr/pub/docs/manual-ocaml/manual019.html#@manual.kwd170)和[include]( http://caml.inria.fr/pub/docs/manual-ocaml/manual019.html#@manual.kwd171)。 – 2012-04-03 18:12:13

回答

11

你有两个级别的机器人。由于您明确地在文件robot.ml中调用了模块“Robot”,因此您需要打开Robot并调用Robot.top()。 robot.ml文件中的任何内容都已隐式地放置在Robot模块中。

您可以摆脱robot.ml中额外的'module Robot'声明。

robot.ml将成为:

module type RobotSignature = 
sig 
    val top: unit -> unit 
end 


let top() = 
    begin 
     Printf.printf "top\n" 
    end 

那么它应该工作,你必须在你的main.ml.基于下面的评论

更新:如果当你打开机器人的担心,一切在robot.ml现在将是可见的,你可以定义一个robot.mli文件指定哪个是外部可用的功能。例如,假设您在robot.ml添加一个名为帮手功能:

let top() = 
    begin 
    Printf.printf "top\n" 
    end 

let helper() = 
    Printf.printf "helper\n" 

...然后你定义robot.mli如下:

val top: unit -> unit 

然后让我们说你尝试从main调用helper。毫升:

open Robot;; 

top(); 
(* helper will not be visible here and you'll get a compile error*) 
helper() 

然后,当你尝试编译你会得到一个错误:

$ ocamlc -o main robot.mli robot.ml main.ml 
File "main.ml", line 4, characters 0-6: 
Error: Unbound value helper 
+0

事实上,但现在签名并没有任何效果,因为所有东西都可以从主体中看到。我了解“机器人的两个层次”,但不知道如何修复它,同时保持有用的签名。 – 2012-04-03 17:06:26

+0

如果你想确保只有机器人模块内的模块在主模块内可见,那么定义一个robot.mli文件,它只导出你想要导出的内容(我将编辑我的上面的响应来显示它)。 – aneccodeal 2012-04-03 17:10:57

5

你有两种方法可以做到这一点:

  • 首先,你可以限制你的子结构必须是正确的签名:

    module Robot : RobotSignature = struct ... end 
    

    然后在main.ml,你可以做open Robot.Robot:第一Robot意味着相关联robot.ml编译单元,第二Robot是你里面robot.ml

  • 定义的子模块还可以删除一个台阶,创造robot.mli包含:

    val top: unit -> unit 
    

    robot.ml含有:

    let top() = 
        Printf.printf "top\n" 
    
    (* Should not be visible from the 'main' *) 
    let dummy() = 
        Printf.printf "dummy\n" 
    

    您可以使用编译模块,然后在main.ml中简单使用open Robot

+0

或者更好的不要打开机器人,而是调用Robot.top()。 – 2012-04-03 17:59:16

+0

如果'''Robot.Robot.top'''对于频繁使用来说太长了,写'''让模块R = Robot.Robot in R.top''' – lambdapower 2012-04-03 20:12:31