ocaml中的回避对象
作为一个学习项目,我试图用OCaml编写一个简单的塔防游戏,但我在如何构造代码方面遇到了问题。我一直在试图避免使用类/对象来表示我的塔和敌人,主要是因为我还没有了解ocaml对象是如何工作的,但主要是因为我似乎从阅读有关ocaml的文章中发现了对使用它们的厌恶。不管怎样,我一直在尝试为每种类型的塔都提供一个模块,它们都有相同的签名(ocaml中的回避对象,ocaml,Ocaml,作为一个学习项目,我试图用OCaml编写一个简单的塔防游戏,但我在如何构造代码方面遇到了问题。我一直在试图避免使用类/对象来表示我的塔和敌人,主要是因为我还没有了解ocaml对象是如何工作的,但主要是因为我似乎从阅读有关ocaml的文章中发现了对使用它们的厌恶。不管怎样,我一直在尝试为每种类型的塔都提供一个模块,它们都有相同的签名(tower),实现mainloop用来更新游戏的功能。我的想法是使用第一类模块,这样我就可以有一个 let create m = let module M = (
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小部件和游戏图片。您可以使用记录,也可以使用第一类模块,但对象和继承就是为了这个目的而创建的。不要恨你不知道的东西,学会它,这样你才能真正地恨它。:)