我目前正在享受从面向对象语言到功能语言的转变。这是一股清新的空气,我发现自己比以前更富有成效。
但是 - 有一个方面的OOP我还没有在FP方面看到令人满意的答案,那就是多态。即我有大量的数据项,当它们被传递到某些功能时需要以完全不同的方式处理。为了论证,让我们说有多种因素推动多态行为,因此潜在地指数多种不同的行为组合。
在使用多态性可以相对较好地处理的OOP中:通过组合+继承或基于原型的方法。
在FP中我有点卡在:
针对这种情况推荐的功能方法是什么?还有其他好的选择吗?
答案 0 :(得分:21)
以类似原型的方式将函数放入纯数据结构中 - 这似乎有效但是它是否也违反了从数据中单独定义纯函数的想法?
如果虚拟方法调度是您想要解决问题的方式,那么这是一种非常合理的方法。至于将功能与数据分开,这是一个明显无功能的概念。我认为函数式编程的基本原理是函数ARE数据。至于你是否觉得你正在模拟一个虚拟函数,我认为它根本不是模拟。它是一个虚拟功能表,这完全没问题。
仅仅因为语言没有内置的OOP支持并不意味着应用相同的设计原则是不合理的 - 它只是意味着你必须编写更多内置其他语言提供的机器,因为你正在与你正在使用的语言的自然精神作斗争。现代类型函数式语言对多态性有很强的支持,但它是一种非常不同的多态方法。
OOP中的多态性很像逻辑中的“存在量化” - 多态值具有某种运行时类型,但您不知道它是什么。在许多函数式编程语言中,多态性更像是“通用量化” - 多态值可以实例化为其用户想要的任何兼容类型。它们是完全相同硬币的两面(特别是,它们根据您是从“内部”还是“外部”查看功能而交换位置),但在设计时却非常困难。 “使硬币公平”的语言,特别是在存在其他语言特征的情况下,例如亚型或更高级别的多态性(多态性与多态类型)。
如果它有帮助,你可能想要将函数式语言中的多态性视为非常类似于C#或Java中的“泛型”,因为这正是多态的类型,例如ML和Haskell,它。
答案 1 :(得分:12)
好吧,在Haskell中,你总是可以创建一个类类来实现一种多态。基本上,它定义了为不同类型处理的函数。示例包括类Eq
和Show
:
data Foo = Bar | Baz
instance Show Foo where
show Bar = 'bar'
show Baz = 'baz'
main = putStrLn $ show Bar
为类型show :: (Show a) => a -> String
实例的每种数据类型定义函数Show
。编译器会为您找到正确的函数,具体取决于类型。
这允许更一般地定义函数,例如:
compare a b = a < b
将适用于任何类型的类型类Ord
。这与OOP不完全相同,但你甚至可以继承像这样的类型类:
class (Show a) => Combinator a where
combine :: a -> a -> String
由实例来定义实际函数,您只需定义类型 - 类似于虚函数。
这还不完整,据我所知,许多FP语言都没有类型类。 OCaml没有,它将其推到其OOP部分。而Scheme没有任何类型。但在Haskell中,它是在一定范围内实现某种多态性的有效方法。
更进一步,2010标准的新扩展允许类型系列等。
希望这对你有所帮助。
答案 2 :(得分:11)
谁说
与数据分开定义纯函数
是最佳做法吗?
如果你想要多态对象,你需要对象。在功能语言中,可以通过将一组“纯数据”与对该数据进行操作的一组“纯函数”粘合在一起来构造对象。即使没有类的概念,这也可以工作。从这个意义上说,一个类只不过是一段用相同的“纯函数”构造对象的代码。
通过用具有相同签名的不同函数替换对象的一些函数来构造多态对象。
如果您想了解有关如何使用函数式语言(如Scheme)实现对象的更多信息,请查看本书:
Abelson / Sussman: "Structure and Interpration of Computer programs"
答案 3 :(得分:4)
该方案没有内置系统的原因是使用错误的对象系统导致问题导致各种麻烦,所以如果你是语言设计师,可以选择哪种?单个发送单个继承不能很好地处理“驱动多态行为的多个因素,因此可能会成倍地指数多种不同的行为组合。”
要进行synopsize,有许多构造对象的方法,而SICP中讨论的语言方案只是为您提供了一个基本的工具包,您可以从中构建所需的工具包。
在真正的方案程序中,您手动构建对象系统,然后使用宏隐藏相关的样板文件。
在clojure中,你实际上有一个使用multimethods内置的预构建对象/调度系统,与传统方法相比,它的一个优点是它可以调度所有参数的类型。您(显然)也可以使用层次结构系统为您提供类似继承的功能,虽然我从未使用它,所以您应该使用 cum grano salis 。
但是如果你需要与语言设计师选择的对象方案不同的东西,你可以制作一个(或几个)适合的对象。
这实际上就是你提出的建议。
构建您需要的东西,让它全部工作,用宏隐藏细节。
FP和OO之间的争论不是关于数据抽象是否糟糕,而是关于数据抽象系统是否适合填充程序的所有单独关注点。
“我相信编程语言应该允许人们定义新的数据类型。我不认为程序应该只包含新数据类型的定义。”
答案 4 :(得分:1)