ocaml中的回避对象

ocaml中的回避对象,ocaml,Ocaml,作为一个学习项目,我试图用OCaml编写一个简单的塔防游戏,但我在如何构造代码方面遇到了问题。我一直在试图避免使用类/对象来表示我的塔和敌人,主要是因为我还没有了解ocaml对象是如何工作的,但主要是因为我似乎从阅读有关ocaml的文章中发现了对使用它们的厌恶。不管怎样,我一直在尝试为每种类型的塔都提供一个模块,它们都有相同的签名(tower),实现mainloop用来更新游戏的功能。我的想法是使用第一类模块,这样我就可以有一个 let create m = let module M = (

作为一个学习项目,我试图用OCaml编写一个简单的塔防游戏,但我在如何构造代码方面遇到了问题。我一直在试图避免使用类/对象来表示我的塔和敌人,主要是因为我还没有了解ocaml对象是如何工作的,但主要是因为我似乎从阅读有关ocaml的文章中发现了对使用它们的厌恶。不管怎样,我一直在尝试为每种类型的塔都提供一个模块,它们都有相同的签名(
tower
),实现mainloop用来更新游戏的功能。我的想法是使用第一类模块,这样我就可以有一个

let create m =
  let module M = (val m : TOWER) in
  M.create ()
其中,

module type TOWER = sig
  type t
  ...
  val create : unit -> t
end

但现在我有一个问题,当你打开一个第一类模块时,你会得到一个全新的模块,而我假设你会得到一个类似于模块别名的东西,因此,在编译时,我得到一个错误,说M.t的类型构造函数的范围有问题。从这一点和我尝试进行的修补来看,我最初的想法似乎是使用第一类模块来决定要使用哪个函数,除非我将类型声明移出
TOWER
,并使其成为一个共享的类型所有的塔都使用。有没有一种方法可以达到我想要的效果,或者我必须使用其他技术?

如果在函数中使用一个第一类模块,并且函数类型中存在一个类型构造函数,它取决于模块中定义的类型,那么这意味着该类型将脱离其作用域,你需要把你的函数变成一个prenex标准形式,把这个类型绑定到一个新的类型变量上。为了澄清这一点,以下是一个例子:

let create_tower (module T : TOWER) = T.create ()
这将不会编译,因为
T.T.
会跳出范围。尝试为函数
create_tower
(模块塔)->?
编写一个类型。我们没有类型
t
的名称,该类型在
签名的范围内。所以我们需要把它拿出来,得到以下类型:

(module TOWER with type t = 'a) -> 'a 
为此,我们使用以下语法:

let create_tower (type t) (module T : TOWER with type t = t) = 
  T.create ()
现在它起作用了


还有一个关于模块的常见咆哮。这里不需要使用模块或对象。只需使用记录来表示你的塔和敌人

如果在函数中使用第一类模块,并且函数类型中存在一个类型构造函数,该构造函数取决于模块中定义的类型,那么这意味着该类型将脱离其范围,您需要通过将该类型绑定到新的类型变量,将函数放入prenex范式中。为了澄清这一点,以下是一个例子:

let create_tower (module T : TOWER) = T.create ()
这将不会编译,因为
T.T.
会跳出范围。尝试为函数
create_tower
(模块塔)->?
编写一个类型。我们没有类型
t
的名称,该类型在
签名的范围内。所以我们需要把它拿出来,得到以下类型:

(module TOWER with type t = 'a) -> 'a 
为此,我们使用以下语法:

let create_tower (type t) (module T : TOWER with type t = t) = 
  T.create ()
现在它起作用了


还有一个关于模块的常见咆哮。这里不需要使用模块或对象。只需使用记录来表示你的塔和敌人

如果使用sum类型来表示不同的塔,则不必费心处理模块或对象

例如:

type tower =
| SimpleTower 
| SuperTower of int

type position = int * int

type pos_tower = position * tower

let string_of_tower = function
  | SimpleTower -> "Simple tower"
  | SuperTower i -> "Super Tower level " ^ (string_of_int i)

;;


let my_towers = [ ((0,0) , SimpleTower) ; ( (10,0) , SuperTower 5) ] ;;

这种体系结构的属性与面向对象体系结构的属性是双重的(这里的功能是模块化的,而它们在对象体系结构中是横切的)。

如果您使用求和类型来表示不同的塔,您不必为模块或对象而烦恼

例如:

type tower =
| SimpleTower 
| SuperTower of int

type position = int * int

type pos_tower = position * tower

let string_of_tower = function
  | SimpleTower -> "Simple tower"
  | SuperTower i -> "Super Tower level " ^ (string_of_int i)

;;


let my_towers = [ ((0,0) , SimpleTower) ; ( (10,0) , SuperTower 5) ] ;;

这种体系结构的属性与面向对象体系结构的属性是双重的(这里的功能是模块化的,而它们在对象体系结构中是横切的)。

您能告诉我们您的展开代码和错误消息吗?我建议您了解对象。有两个字段非常适合对象概念,它们是GUI小部件和游戏图片。您可以使用记录,也可以使用第一类模块,但对象和继承就是为了这个目的而创建的。不要恨你不知道的东西,学会它,这样你才能真正地恨它。:)你能给我们看一下你的解包代码和错误信息吗?我建议你了解对象。有两个字段非常适合对象概念,它们是GUI小部件和游戏图片。您可以使用记录,也可以使用第一类模块,但对象和继承就是为了这个目的而创建的。不要恨你不知道的东西,学会它,这样你才能真正地恨它。:)