是否有用于函数式编程的软件工程方法?

Tho*_*ten 202 lisp functional-programming clojure model-driven-development

今天教授的软件工程完全专注于面向对象的编程和面向世界的"自然"面向对象的视图.有一个详细的方法描述了如何将域模型转换为具有多个步骤的类模型以及许多(UML)工件,如用例图或类图.许多程序员已经内化了这种方法,并且很好地了解了如何从头开始设计面向对象的应用程序.

新的炒作是函数式编程,在许多书籍和教程中都有教授.但功能软件工程呢?在阅读有关Lisp和Clojure的文章时,我发现了两个有趣的陈述:

  1. 功能程序通常是自下而上而不是自上而下开发('On Lisp',Paul Graham)

  2. 函数程序员使用映射,其中OO程序员使用对象/类('Clojure for Java Programmers',Rich Hickley的演讲).

那么功能性应用程序的系统化(基于模型的?)设计的方法是什么,即在Lisp或Clojure中?有哪些常见步骤,我使用哪些工件,如何将它们从问题空间映射到解决方案空间?

Nor*_*sey 162

感谢上帝,软件工程人员还没有发现函数式编程.以下是一些相似之处:

  • 许多OO"设计模式"被捕获为高阶函数.例如,访客模式在功能世界中被称为"折叠"(或者如果你是一个尖头理论家,那就是"catamorphism").在函数式语言中,数据类型主要是树或元组,并且每种树类型都具有与之相关的自然变形.

    这些高阶函数通常伴随着某些编程定律,即"自由定理".

  • 功能程序员使用图表的程度远低于OO程序员.OO图中表达的大部分内容都以类型或"签名"表示,您应该将其视为"模块类型".Haskell也有"类型类",有点像接口类型.

    那些使用类型的函数式程序员通常认为"一旦你获得了正确的类型;代码实际上就是自己编写的".

    并非所有函数式语言都使用显式类型,但" 如何设计程序 "一书是一本优秀的学习Scheme/Lisp/Clojure的书,很大程度上依赖于与类型密切相关的"数据描述".

那么功能性应用程序的系统化(基于模型的?)设计的方法是什么,即在Lisp或Clojure中?

任何基于数据抽象的设计方法都能很好地工作.我碰巧认为,当语言具有明确的类型时,这会更容易,但即使没有,它也能正常工作.关于设计方法的抽象数据类型,这是很容易适应函数式编程,良好的开端是抽象和规范的程序开发芭芭拉Liskov的和约翰·加塔的第一版本.利斯科夫为这项工作赢得了图灵奖.

Lisp独有的另一种设计方法是确定哪些语言扩展在您正在使用的问题域中有用,然后使用卫生宏将这些结构添加到您的语言中.关于这种设计的一个好地方是Matthew Flatt的文章" 在Racket中创建语言".这篇文章可能是付费墙的背后.您还可以通过搜索"特定于域的嵌入式语言"这一术语找到有关此类设计的更多常规材料; 除了Matthew Flatt所涵盖的特殊建议和示例之外,我可能会从Graham的On LispANSI Common Lisp开始.

有哪些常见步骤,我使用哪些工件?

常用步骤:

  1. 识别程序中的数据及其上的操作,并定义表示此数据的抽象数据类型.

  2. 确定常见的动作或计算模式,并将它们表示为高阶函数或宏.期望将此步骤作为重构的一部分.

  3. 如果您使用的是键入的函数式语言,请尽早使用类型检查器.如果您使用的是Lisp或Clojure,最佳做法是首先编写函数契约,包括单元测试 - 它是测试驱动开发的最大值.并且您将希望使用已移植到您的平台的任何版本的QuickCheck,在您的情况下,它看起来像是ClojureCheck.它是一个非常强大的库,用于构建使用高阶函数的代码的随机测试.

  • +1"感谢上帝,软件工程人员还没有发现函数式编程." ;) (22认同)
  • @Michael--实际上你可以非常整齐地捕获各种高阶类似的多次调度.杰里米·吉本斯(Jeremy Gibbons)的工作是寻找这个问题的一个地方,但我建议一般的数据类型 - 通用编程工作 - 我特别喜欢复合纸. (6认同)
  • 我同意我看到图表用于描述功能设计的频率低得多,我认为这是一种耻辱.当使用大量HOF时,很难表示序列图的等价物.但我希望如何更好地探索如何用图片描述功能设计的空间.尽管我讨厌UML(作为规范),但我发现UML(作为草图)在Java中非常有用,并希望有关于如何做等效的最佳实践.我一直在尝试用Clojure协议和记录来做这件事,但我真的不喜欢. (6认同)
  • IMO访客不是折叠 - 折叠是访客的子集.折叠不会(直接)捕获多个调度. (2认同)
  • @Norman很棒的回答 (2认同)

cgr*_*and 44

对于Clojure,我建议回到旧的关系建模.在Tar​​pit中是一个鼓舞人心的读物.


mik*_*era 38

就个人而言,我发现OO开发中的所有通常的良好实践也适用于函数式编程 - 只需稍微调整一下即可考虑功能性世界观.从方法论的角度来看,您根本不需要做任何根本不同的事情.

我的经验来自于近年来从Java迁移到Clojure.

一些例子:

  • 了解您的业务领域/数据模型 - 无论您是要设计对象模型还是使用嵌套映射创建功能数据结构,都同样重要.在某些方面,FP可以更容易,因为它鼓励您将数据模型与功能/流程分开考虑,但您仍然必须同时执行这两者.

  • 设计中的服务导向 - 从FP角度来看实际上非常有效,因为典型的服务实际上只是具有一些副作用的功能.我认为在Lisp世界中有时支持的软件开发的"自下而上"观点实际上只是另一种形式的面向服务的API设计原则.

  • 测试驱动开发 - 在FP语言中运行良好,实际上有时甚至更好,因为纯函数非常适合编写清晰,可重复的测试,而无需建立有状态的环境.您可能还想构建单独的测试以检查数据完整性(例如,此映射是否具有我期望的所有键,以平衡在OO语言中类定义将在编译时为您强制执行此操作的事实).

  • Prototying/iteration - 与FP一样好用.如果您非常擅长构建工具/ DSL并在REPL中使用它们,您甚至可以与用户进行实时原型设计.

  • 这些做法对我来说非常熟悉.我仍然认为有人应该使用Bruegge/Dutoit编写的功能等同于"使用UML,模式和Java的面向对象的软件工程"而不是第六本书"Clojure中的编程".它可以被称为"功能软件工程使用Clojure和??什么??".他们在FP中使用UML和模式吗?我记得Paul Graham写道,模式是Lisp缺乏抽象的标志,应该通过引入新的宏来解决. (3认同)
  • 但是,如果您将模式转换为最佳实践,那么FP世界中也可能存在模式,值得与未初始化的模式共享. (3认同)
  • PAIP书中有一些有趣的原则设计.http://norvig.com/paip.html (2认同)

scl*_*clv 13

OO编程将数据与行为紧密耦合.功能编程将两者分开.所以你没有类图,但是你有数据结构,特别是你有代数数据类型.可以编写这些类型以非常紧密地匹配您的域,包括通过构造消除不可能的值.

所以没有关于它的书籍和书籍,但有一种完善的方法,正如俗话所说,使不可能的价值观无法代表.

在这样做时,您可以做出一系列选择,将某些类型的数据表示为函数,相反,将某些函数表示为数据类型的并集,以便您可以获得,例如,序列化,更严格的规范,优化等.

然后,鉴于此,您在adts上编写函数,以便建立某种代数 - 即有固定的法则适用于这些函数.有些可能是幂等的 - 在多次应用之后也是如此.有些是联想的.有些是传递性的,等等.

现在,您拥有一个域,您可以根据良好的法律构建函数.一个简单的嵌入式DSL!

哦,给定属性,你当然可以编写自动随机测试(ala QuickCheck)..而这只是一个开始.


Kaz*_*Kaz 7

面向对象的设计与软件工程不同.软件工程与我们如何从需求到工作系统,按时和低缺陷率的整个过程有关.功能编程可能与OO不同,但它不会消除需求,高级和详细设计,验证和测试,软件度量,估计以及所有其他"软件工程".

此外,功能程序确实展示了模块化和其他结构.您的详细设计必须以该结构中的概念来表达.


Jam*_*ery 5

一种方法是在所选择的函数编程语言中创建内部DSL.然后,"模型"是在DSL中表达的一组业务规则.

  • 但是,当“模型是用 DSL 表达的一组业务规则”时,它会是什么样子呢?例如,在 Java EE 应用程序中,模型被编写为 POJO 实体,从控制器 EJB 调用,而控制器 EJB 又更新视图 JSP。FP 中是否有类似的架构模式(如 MVC 模式)?看起来怎么样? (2认同)
  • 没有理由你不能在FP中拥有MVC模式,就像那样.FP仍然允许您构建丰富的数据结构,并且可以说与ADT和模式匹配,可以让您构建更丰富的*更多.如果有的话,由于FP分离数据和行为,MVC类型系统更自然地出现. (2认同)

drc*_*ode 5

看到我对另一篇文章的回答:

Clojure如何实现关注点分离?

我同意有关如何构建使用FP方法的大型应用程序的更多需求(还有更多需要用来记录FP驱动的UI)

  • 我喜欢90%的管道和10%的宏观方法.将函数式程序视为不可变数据转换的管道似乎很自然.我不确定我是否理解你的意思是"将所有智能放入数据,而不是代码",因为100个函数处理1个数据结构(而不​​是10个数据结构上的10个函数)的方法似乎意味着相反的.OOP中的数据结构是否比FP更智能,因为它们有自己的行为内置? (3认同)