函数式编程中的扩展技术,如F#

时间:2010-12-22 09:03:13

标签: f# functional-programming

在面向对象编程中,继承和虚拟方法是创建可扩展代码的常见方案。在更复杂的设置中,工厂方法(或依赖框架)有助于扩展基本代码。

创建可扩展代码的函数式编程(例如F#)有哪些常用方法?

2 个答案:

答案 0 :(得分:10)

很棒的问题!

以下是从this blog article得出的答案:

功能范例(意味着使用高阶函数)仅提供单一形式的可扩展性:高阶函数。这些允许您分解“内部”功能。例如,经常出现相同的第一个和最后一个代码块的代码:

let f x =
  first x
  stuff1 x
  last x

let g x =
  first x
  stuff2 x
  last x

可以被考虑到从特定情况重用的一般高阶函数中:

let hof stuff x =
  first x
  stuff x
  last x

let f = hof stuff1 x

let g = hof stuff2 x

积极地应用它会导致设计模式,例如解析器组合器,并且是一种非常强大且轻量级的技术,可以使代码可扩展。但是,它不会使数据类型可扩展。

但是真正的函数式编程语言几乎总是包含更有趣的语言功能来帮助实现可扩展性:

  • Common Lisp具有Common Lisp对象系统(CLOS)和宏系统。
  • 标准ML具有参数多态性和高阶模块系统。
  • OCaml添加了多态变体,对象,可选参数和Camlp4宏系统。
  • Haskell具有参数多态和类型类,而Template Haskell添加了宏。
  • Scala具有Java风格的OOP,并具有一些附加功能。

阅读Chris Okasaki的优秀专着Purely功能数据结构,用于使用标准ML中的高阶模块和Haskell中的类型类的一些很好的例子。请阅读Jacques Garrigue的Code reuse through polymorphic variants,了解该语言功能如何用于攻击表达式问题。然而,这些解决方案在野外是非常罕见的,特别是没有它们你可以走很长的路(例如在F#中)。

从历史上看,这种多样性的出现是因为大多数函数式编程语言都是研究项目,因此,它们的存在增加了新的特性。因此,我们现在在当今的函数式编程语言中有各种各样的不同形式的可扩展性。

F#是一种不同的野兽,因为它的设计要求是与.NET的其余部分(强加.NET风格的OOP)和实用主义的无缝互操作性。因此,F#保持ML核心具有参数多态性并添加.NET的对象系统。因此,您可以从通用高阶函数和传统OOP提供的简单可扩展性中受益,但不能从任何更深奥的功能(如高阶模块,类型类和宏)中获益。

F#开创性的唯一可扩展性形式是活跃模式。这些允许您将通过模式匹配进行结构化的代码与具体数据表示分开。这是将代码与数据分离的重要方法,因此可以使其更具可重用性。

答案 1 :(得分:4)

函数式编程的基本扩展技术是

  • 编写高阶函数(将其他函数作为参数的函数)
  • (功能)多态(使用按类型参数化的函数和类型 - 在C#术语,泛型类型和方法中)。

例如,您可能不会使用抽象方法(修改对象的某些状态),而是将函数作为参数传递。该函数将采取所有必要的状态来进行计算(由OO中的抽象方法完成)并且它将返回新状态(或者无论计算结果如何)。

list<T>等通用(多态)代码是扩展技术的另一个例子。您有一些数据结构和函数(例如List.map),您可以将它与以前未知的类型(列表项的类型)一起使用,并指定特定于此类型的行为(例如,过滤谓词)。列表是非常基本的示例,但它也适用于非集合类型。

在更复杂的设置中,编程语言之间存在较大差异

  • 在Haskell中,人们可能会使用类型类(有点像更强大的接口)
  • 在OCaml中,人们使用仿函数(类似于经典的函数多态,但您也可以通过多种函数和类型进行参数化)。
  • 在F#中,我认为,人们通常将标准.NET技术(如接口)与基本功能技术(高阶函数,将函数作为参数传递给对象构造函数等)混合使用。

FP和OO的这种组合是一个非常强大的组合,所以你可能不需要像依赖框架那样复杂的东西。