在函数式编程中实现多态

目前我正在享受从面向对象语言到function语言的转变。 这是一股清新的空气,我发现自己比以前更富有成效。

然而 – OOP的一个方面,我还没有看到FP方面令人满意的答案,那就是多态 。 即我有大量的数据项,当它们被传递到某些函数时需要以不同的方式处理。 为了论证,假设有多种因素推动多态行为,所以潜在地呈指数forms的许多不同的行为组合。

在OOP中,可以使用多态性相对较好地处理:通过组合+inheritance或基于原型的方法。

在FP我有点卡住之间:

  • 编写或编写纯粹的函数,通过分支每个数据项的值有效地实现多态行为 – 感觉就像组装一个巨大的条件表,甚至模拟一个虚拟方法表!
  • 把函数放在纯数据结构中,就像原型一样 – 这看起来像是起作用,但是这不违背定义与数据分开的纯函数的思想吗?

什么是这种情况推荐的function方法? 还有其他好的select吗?

把函数放在纯数据结构中,就像原型一样 – 这看起来像是起作用,但是这不违背定义与数据分开的纯函数的思想吗?

如果虚拟方法调度是你想要解决问题的方式,这是一个完全合理的方法。 至于从数据分离function,这是一个明显不起作用的概念。 我认为函数式编程的基本原理就是函数是数据。 至于你的模拟虚拟function的感觉,我认为这不是一个模拟。 这是一个虚拟的function表,这是完全正确的。

仅仅因为语言没有内置的OOP支持,并不意味着使用相同的devise原则是不合理的 – 这意味着你必须编写更多的其他语言提供的内置机制,重新对抗你使用的语言的自然精神。 现代types化的函数式语言确实对多态性有很深的支持,但是对多态性来说却是一种非常不同的方法。

OOP中的多态性很像逻辑中的“存在量化” – 多态值有一些运行时types,但是你不知道它是什么。 在许多函数式编程语言中,多态性更像是“通用量化” – 多态值可以被实例化为用户需要的任何兼容types。 他们是完全相同的硬币的两面(特别是,他们交换的地方取决于你是否在看“内部”或“外部”的function),但事实certificate,在devise语言来“使硬币公平”,特别是在存在其他语言特征(例如子types或更高主体多态性(多态性多态性types))的情况下。

如果有帮助的话,你可能想把函数式语言中的多态性看作非常像C#或Java中的“generics”的东西,因为这正是ML和Haskell所喜欢的多态的types。

那么,在Haskell中,你总是可以创build一个types类来实现一种多态。 基本上,它是定义不同types的function。 示例是类EqShow

 data Foo = Bar | Baz instance Show Foo where show Bar = 'bar' show Baz = 'baz' main = putStrLn $ show Bar 

show :: (Show a) => a -> String函数是为types为Show实例的每个数据types定义的。 编译器根据types为您find正确的函数。

这允许更一般地定义function,例如:

 compare ab = a < b 

将使用任何types的typesOrd 。 这不完全像OOP,但是你甚至可以像这样inheritancetypes类:

 class (Show a) => Combinator a where combine :: a -> a -> String 

定义实际function取决于实例,只定义types – 类似于虚拟function。

这是不完整的,据我所知,许多FP语言不具有types类。 OCaml没有,它把它推到它的OOP部分。 而Scheme没有任何types。 但是在Haskell中,这是一种在范围内实现一种多态的强大方法。

更进一步,2010年标准的更新扩展允许types家庭等。

希望这对你有所帮助。

谁说

定义与数据分开的纯函数

是最佳做法?

如果你想要多态对象,你需要对象。 在一种function语言中,可以通过将一组“纯数据”与一组在操作该数据的“纯函数”粘合在一起来构build对象。 即使没有类的概念,这也是有效的。 从这个意义上说,一个类只不过是一段代码,它用相同的一组相关“纯函数”来构造对象。

多态对象是通过用相同的签名来replace对象的某些函数的不同function来构造的。

如果你想了解更多关于如何用函数式语言实现对象(比如Scheme),请看一下这本书:

Abelson / Sussman:“计算机程序的结构和交互”

迈克,你的方法都是完全可以接受的,正如布朗博士在SICP第二章中所说的那样,讨论每种方法的优缺点。 第一个患有大型表的地方,需要维护。 第二个传统的单调度多态/虚函数表。

scheme中没有内置系统的原因是,使用错误的对象系统来解决问题会带来种种麻烦,所以如果你是语言devise者,哪一个可以select? 单一派遣单一inheritance将不能很好地处理“推动多态行为的多重因素,因此可能呈指数级地增加许多不同的行为组合”。

概括来说,构造对象的方法有很多种,而SICP中讨论的语言scheme只是给你一个基本的工具包,你可以从中构build出你需要的。

在真正的scheme程序中,您需要手动构build对象系统,然后使用macros隐藏相关的样板。

在clojure中,实际上有一个用多方法构build的预构build对象/调度系统,与传统方法相比,它的一个优点是它可以派发所有参数的types。 你可以(显然)也使用heirarchy系统给你类似inheritance的function,虽然我从来没有使用它,所以你应该采取那个暨grano salis

但是如果你需要与语言devise者select的对象scheme不同的东西,你可以制作一个(或几个)适合的对象。

这正是你上面提出的。

build立你所需要的,让所有的工作,用macros隐藏的细节。

FP和OO之间的争论不在于数据抽象是否不好,而在于数据抽象系统是否是填补程序所有单独关注的地方。

“我相信一种编程语言应该允许我们定义新的数据types,我不相信一个程序应该只包含新数据types的定义。”