函数式编程的原理,最佳实践和设计模式

时间:2009-05-08 22:06:19

标签: design-patterns functional-programming principles

在使用函数式编程语言编写代码时,是否有任何已知的原则,最佳实践和设计模式?

7 个答案:

答案 0 :(得分:20)

有折叠,展开,地图等。

我考虑使用它们的最佳实践,因为它很容易推理出他们的行为,并且他们经常传达函数的目的(举个例子,看看着名的Evolution of a Haskell Programmer和对比新生与大四和教授一起。)

答案 1 :(得分:10)

设计模式:让类型指导您的编码

  1. 找出您要返回的类型。

  2. 知道某些类型构造函数具有某种语法,并利用它来使所需类型更小。以下是两个例子:

    • 如果您尝试返回函数类型T1 -> T2始终可以安全地编写

      \ x -> ...
      

      现在你正在尝试生成T2类型的值,这是一个较小的类型,另外你还获得了x类型的额外值T1,让你的工作更轻松。

      如果lambda变得不必要,你可以随时将其减少。

    • 如果您尝试生成一对(T1, T2)类型,则始终可以尝试生成x类型的值T1和值y类型T2,然后形成对(x, y)。同样,您已将问题简化为类型较小的问题。

  3. 一旦类型尽可能小,可以查看范围内所有let-bound和lambda-bound变量的类型,并了解如何生成所需类型的值。通常,您希望使用所有函数的所有参数;如果你不这样做,请务必解释原因。

  4. 在许多情况下,特别是在编写多态函数时,这种设计技术可以将复杂函数的构造减少到一两个选项。这些类型指导程序的构造,因此很少有方法可以编写正确类型的函数 - 通常只有一种方法没有明显错误。

答案 2 :(得分:8)

最佳实践:使用代数数据类型并利用模式匹配编译器中的穷举检查。特别是,

  • 永远不要匹配顶级的通配符模式_

  • 设置编译器选项,以便模式匹配中缺少的大小写是错误,而不是警告。

答案 3 :(得分:7)

不要遵循原则,遵循你的鼻子。保持功能简短。寻找降低代码复杂程度的方法,这通常但不一定意味着最简洁的代码。了解如何使用内置的高阶函数。

在编写函数后立即重构并减小函数的代码大小。这节省了时间,因为明天你不会有问题&解决方案在你的脑海里。

答案 4 :(得分:4)

设计模式:让编译器为您的函数推断类型,并确保这些类型完全符合您的预期。如果类型更具多态性或更少多态,请找出原因。

例如,如果您正在Haskell中编写排序函数,那么期待

Ord a => [a] -> [a]

如果您的类型是

Num a => [a] -> [a]

[a] -> b

然后出现了可怕的错误。

最佳实践:一旦您使用编译器确认类型符合您的预期,就会为每个顶级函数设置一个显式类型签名。 (或者,如果您使用的是ML或Caml,请编写显式接口。)设置编译器选项,使缺少签名的值触发错误。

答案 5 :(得分:3)

我的回答可能有点模糊:努力使你的代码美丽作为最重要的方面。致quote David Gelernter:

  

美丽在计算领域比其他任何技术都重要,因为软件非常复杂。美是对抗复杂性的最终防御。

和Brian Kernighan:

  

控制复杂性是计算机编程的本质。

如果您追求这个目标,它将引导您编写易于阅读并理解(这非常重要)的代码,将代码拆分为具有明确目的的小型紧凑部件。它将引导您学习如何以最佳方式表达您的想法。

(所有这些并不仅仅适用于函数式语言,但编写漂亮的代码对它们来说要容易得多。)

答案 6 :(得分:2)

John Hughes的

Why Functional Programming Matters给出了很好的动机,为什么懒惰和高阶(一等)函数提供了很多功能较少的语言missing and supplement with design patterns

在Haskell的上下文中,我认为本书Real World Haskell对习语和抽象以及类型类等有一些好的和实用的建议。 Typeclassopedia也总是有用的。核心的,非常抽象的类型类可以看作是设计模式,除了它们由编译器/类型系统和部分语言强制执行(如果你学习如何使用它们)。

在Lisp的上下文中,Paul Graham写了一本名为On Lisp(available online)的书,他表明函数式语言是创建自定义编程语言然后编写程序的理想选择。因此,嵌入式域特定语言本身就是一种设计模式。