马丁·奥德斯基( Martin )完成了一个关于Scala的在线课程,有一个未回答的问题:
我们能不能用另一个概念来实现一个概念?
很明显,高阶函数可以使用对象来实现,但我不确定它是相反的,还是至少在使用静态类型的时候。
假设闭包可以像对象一样包含封装的数据,但是它的接口中仍然只有一个“方法”--应用它自己。在动态语言中(或者在静态语言中,如果我们使用一些广泛的类型,如Object
或Any
),我们可以传递和返回这个函数中的任何内容,但这真的是一个对象吗?
发布于 2015-12-26 06:46:25
使用动态类型,在闭包方面实现一个面向对象的系统是相当简单的。我在我对“把物体建模为函数”的回答和在我的博客上扩展了这方面的内容上写过这方面的文章。对于获得某些OOP特性(如子类权限)来说,有一些关于开放递归的详细信息是必要的,但它是可行的。简而言之,调用表示对象的闭包将方法名称映射到绑定到该对象的方法,然后该方法可以作为普通函数调用。用法可能类似于result = object("methodName")(otherObject)
。
然而,OOP和静态类型从根本上说是不一致的。对OOP有不同的解释,例如作为消息传递的OOP或作为虚拟调度的OOP,但中心主题是我们不静态地知道表达式(如x
)的确切运行时类型。但是,许多静态类型的OOP语言确实为表达式分配类型界限(例如x
是Iterable
的一个子类型)。当用静态类型语言以闭包的形式实现对象时,我们很快就会遇到问题--当将所需的方法指定为分派函数的参数时,我们无法静态地知道函数所需的签名。在上面的例子中,我如何知道object("methodName")
的结果应该是接受一个参数的函数?
实现对象时的常见解决方案是使对象-系统统一(又名)。(未输入)也就是说,所有方法签名都将具有相同的类型,而不管它们的重要性(参数的数量)或参数的类型。这还要求我们的所有对象在宿主语言中具有相同的类型。
有些语言可能会做得更好。例如,在C++中,我们可以将请求的方法类型作为模板参数传递给分派函数:auto result = object<ResultType(ArgumentType)>("methodName")(otherObject)
。聪明的实现可以使用不同的查找表来分派int()
或int(int)
方法类型等。但是,我们不能静态地保证请求的方法存在,因为它是作为字符串提供的。另一种可能是将(类似于访问者的?) Message
对象而不是字符串名称传递给分派函数,这可能允许在静态类型的主机语言中实现更多的类型安全性,但我在用静态语言实现OOP方面没有足够的经验来更详细地描述这一点。
发布于 2015-12-26 06:27:30
有效,是。闭包和对象是等价的。高阶函数更值得商榷。如果局部变量没有闭包(或者如果局部变量在您的语言中是不可变的),则伪对象中不可能有可变字段。如果你只能得到不可变的对象的排序,那么人们就会更容易地认为它们不像对象。
但是,从概念的角度来看,通常应该将闭包和对象看作类似的But。例如,在C#中,闭包是通过类实现的。我希望Scala也会这么做。
发布于 2015-12-26 06:44:35
您可以将对象看作是关闭对象成员变量的闭包,每次使用方法名称调用对象时,它都返回一个方法实现。然后,可以将返回的方法实现应用于实际的方法参数。
由于这个闭包的结果是一个过程/函数(一个方法实现),它实际上是一个高阶函数:高阶函数是一个函数,它要么接受函数作为输入参数,要么作为结果返回一个函数。
https://softwareengineering.stackexchange.com/questions/305894
复制