OCaml 中的访问者设计模式
我正在尝试使用 OCaml 的 OO 构造和类型系统来实现访问者设计模式,但在实例化元素时遇到了问题。
class virtual ['hrRep] employee = object
method virtual receiveEvaluation : 'hrRep -> unit
method virtual getName : string
end;;
class ['hrRep] accountant myName = object (self : 'a)
inherit ['hrRep]employee
val name = myName
method receiveEvaluation rep = rep#visitAccountant self
method getName = name
end;;
class ['hrRep] salesman myName = object (self : 'a)
inherit ['hrRep]employee
val name = myName
method receiveEvaluation rep = rep#visitSalesman self
method getName = name
end;;
class virtual ['accountant, 'salesman] hrRep = object (self)
method virtual visitSalesman : 'salesman -> unit
method virtual visitAccountant : 'accountant -> unit
end;;
class ['employee, 'salesman] lowerLevelHRRep =
object (self) inherit ['employee, 'salesman]hrRep
method visitSalesman s = print_endline ("Visiting salesman "^s#getName)
method visitAccountant a =
print_endline ("Visiting accountant "^a#getName)
end;;
let s1 : (<visitSalesman : 'a -> unit>) salesman = new salesman "Bob";;
let a1 : (<visitAccountant : 'a -> unit>) accountant = new accountant "Mary";;
let s2 : (<visitSalesman : 'a -> unit>) salesman = new salesman "Sue";;
let h1 : (<getName : string>, <getName : string>) lowerLevelHRRep = new lowerLevelHRRep;;
s1#receiveEvaluation h1;;
我在编译时得到的错误是:
The type of this expression, <visitSalesman : 'a -> unit; _.. > salesman as 'a,
contains type variables that cannot be generalized.
然而,代码编译时减去了实例化销售员的行。
如何在维护类功能的同时实例化 salesman
?
编辑 调用 receiveEvaluation 时收到错误:
This expression has type (<getName:string>, < getName:string>) lowerLevelHRRep
but is here used with type <visitSalesman : 'a salesman -> unit > as 'a.
第二个对象类型没有方法 visitAccountant
。
I am attempting to implement the Visitor Design Pattern using OCaml's OO constructs and type system and am running into problems upon instantiation of an Element.
class virtual ['hrRep] employee = object
method virtual receiveEvaluation : 'hrRep -> unit
method virtual getName : string
end;;
class ['hrRep] accountant myName = object (self : 'a)
inherit ['hrRep]employee
val name = myName
method receiveEvaluation rep = rep#visitAccountant self
method getName = name
end;;
class ['hrRep] salesman myName = object (self : 'a)
inherit ['hrRep]employee
val name = myName
method receiveEvaluation rep = rep#visitSalesman self
method getName = name
end;;
class virtual ['accountant, 'salesman] hrRep = object (self)
method virtual visitSalesman : 'salesman -> unit
method virtual visitAccountant : 'accountant -> unit
end;;
class ['employee, 'salesman] lowerLevelHRRep =
object (self) inherit ['employee, 'salesman]hrRep
method visitSalesman s = print_endline ("Visiting salesman "^s#getName)
method visitAccountant a =
print_endline ("Visiting accountant "^a#getName)
end;;
let s1 : (<visitSalesman : 'a -> unit>) salesman = new salesman "Bob";;
let a1 : (<visitAccountant : 'a -> unit>) accountant = new accountant "Mary";;
let s2 : (<visitSalesman : 'a -> unit>) salesman = new salesman "Sue";;
let h1 : (<getName : string>, <getName : string>) lowerLevelHRRep = new lowerLevelHRRep;;
s1#receiveEvaluation h1;;
The error I get upon compilation is:
The type of this expression, <visitSalesman : 'a -> unit; _.. > salesman as 'a,
contains type variables that cannot be generalized.
However, the code compiles minus the line instantiating the salesman
.
How do I go about instantiating the salesman
while maintaining the classes' functionality ?
Edit Error received with call to receiveEvaluation:
This expression has type (<getName:string>, < getName:string>) lowerLevelHRRep
but is here used with type <visitSalesman : 'a salesman -> unit > as 'a.
The second object type has no method visitAccountant
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
编辑 - 将答案分为 3 个要点:初始编译错误的解决方案、递归解决方案和参数化解决方案
编译错误的解决方案
您的代码在顶层工作正常:
请注意, 类型编译错误通常通过添加类型注释来帮助编译器确定类型来解决。 正如顶层善意地告诉我们它是什么一样,我们可以修改实例化:
这可以编译!
递归解决方案
通过使用递归类可以降低复杂性。 这完全消除了对参数化类的需要,但意味着所有对象都需要在同一个源文件中定义。
这将打印“拜访推销员”。 对员工的强制只是为了让这更接近现实世界的场景。
参数化的解决方案
再看一下问题,我认为没有必要有一个参数化的hrRep,因为此时,所有其他类型都是已知的。 通过仅对员工类进行参数化,我得到:
此返回:
拜访销售员 S Bob
拜访会计师 A Mary
拜访推销员 S Sue
该解决方案的优点是员工不需要了解访客,因此可以在他们自己的编译单元,从而在添加新类型的员工时产生更清晰的代码和更少的重新编译。
EDIT - Separated the answer in 3 main points: the resolution of the initial compile error, a recursive solution, and a parametrized solution
Resolution of the compile error
Note that your code works fine in the top level:
This kind of compile error is generally solved by adding a type annotation to help the compiler figuring the type. As the top level kindly told us what it was, we can modify the instantiation:
And this compiles!
A recursive solution
It is possible to reduce complexity by using recursive classes. This totally removes the need for parametrized classes, but means that all objects need to be defined in the same source file.
This prints "Visiting salesman". The coercion to employee is just to make this closer to a real world scenario.
A parametrized solution
Looking at the problem again, I think it is not necessary to have a parametrized hrRep, because at this moment, all other types are known. By just making the employee class parametrized, I get this:
This returns:
Visiting salesman S Bob
Visiting accountant A Mary
Visiting salesman S Sue
The advantage of this solution is that employees do not need to know about the visitor, and therefore can be defined in their own compilation units, leading to cleaner code and less recompilation to do when adding new types of employees.