当今教授的软件工程完全专注于面向对象的编程和“自然”的面向对象的世界观。有一个详细的方法论描述了如何通过几个步骤和许多 (UML) 工件(如用例图或类图)将域模型转换为类模型。许多程序员已经内化了这种方法,并且对如何从头开始设计面向对象的应用程序有了很好的了解。
新的炒作是函数式编程,它在许多书籍和教程中都有讲授。但是功能性软件工程呢?
在阅读 Lisp 和 Clojure 时,我想到了两个有趣的陈述:
函数式程序通常是自下而上而不是自上而下开发的('On Lisp',Paul Graham)
函数式程序员使用映射,而 OO 程序员使用对象/类('Clojure for Java Programmers',Rich Hickley 的演讲)。
那么功能性应用程序的系统(基于模型?)设计的方法是什么,即在 Lisp 或 Clojure 中?常见步骤是什么,我使用什么工件,如何将它们从问题空间映射到解决方案空间?
感谢上帝,软件工程人员还没有发现函数式编程。以下是一些相似之处:
许多 OO“设计模式”被捕获为高阶函数。例如,访问者模式在函数世界中被称为“折叠”(或者,如果您是一个尖头理论家,则称为“变形”)。在函数式语言中,数据类型主要是树或元组,并且每种树类型都有与之关联的自然同构。
这些高阶函数通常伴随着某些编程法则,也就是“自由定理”。
与 OO 程序员相比,函数式程序员较少使用图表。 OO 图中表达的大部分内容都用类型 或“签名”来表达,您应该将其视为“模块类型”。 Haskell 也有“类型类”,有点像接口(interface)类型。
那些使用类型的函数式程序员通常认为“一旦你获得了正确的类型;代码实际上是自己编写的。”
并非所有函数式语言都使用显式类型,但 How To Design Programs本书是一本学习Scheme/Lisp/Clojure的好书,非常依赖与类型密切相关的“数据描述”。
So what is the methodology for a systematic (model-based ?) design of a functional application, i.e. in Lisp or Clojure?
任何基于数据抽象的设计方法都行之有效。我碰巧认为当语言具有显式类型时这会更容易,但即使没有它也能工作。 Barbara Liskov 和 John Guttag 合着的Abstraction and Specification in Program Development是一本关于抽象数据类型设计方法的好书,第一版. Liskov 部分因为这项工作获得了图灵奖。
Lisp 独有的另一种设计方法是确定哪些语言扩展对您正在处理的问题域有用,然后使用卫生宏将这些结构添加到您的语言中。阅读此类设计的好地方是 Matthew Flatt 的文章 Creating Languages in Racket .这篇文章可能在付费专区后面。您还可以通过搜索术语“特定领域的嵌入式语言”来找到有关此类设计的更多一般 Material ;对于超出 Matthew Flatt 涵盖范围的特定建议和示例,我可能会从 Graham 的 On Lisp 开始。或者也许 ANSI Common Lisp .
What are the common steps, what artifacts do I use?
常用步骤:
识别程序中的数据及其操作,并定义表示此数据的抽象数据类型。
识别常见的操作或计算模式,并将它们表示为高阶函数或宏。期望将此步骤作为重构的一部分。
如果您使用的是类型化函数式语言,请尽早并经常使用类型检查器。如果您使用的是 Lisp 或 Clojure,最好的做法是首先编写函数契约,包括单元测试——它是最大程度的测试驱动开发。你会想要使用任何版本的 QuickCheck 已经移植到你的平台,在你的情况下它看起来像被称为 ClojureCheck .它是一个非常强大的库,用于构建使用高阶函数的代码的随机测试。