Principles, Best Practices and Design Patterns for functional programming

血红的双手。 提交于 2019-12-03 03:43:50

问题


Are there any known principles, best-practices and design patterns that one can follow while writing code in a functional programming language?


回答1:


There are folds, unfolds, maps, etc.

I consider using them best practice, as it is pretty easy to reason about their behavior, and they often communicate the purpose of a function (for an example, just take a look at the famous Evolution of a Haskell Programmer and contrast freshman with senior, and with professor).




回答2:


Design pattern: let types guide your coding.

  1. Figure out what type you are trying to return.

  2. Know that certain type constructors come with certain syntax, and exploit it to make the desired type smaller. Here are two examples:

    • If you are trying to return a function type T1 -> T2, it is always safe to write

      \ x -> ...
      

      Now in the body you are trying to produce a value of type T2, which is a smaller type, plus you have gained an extra value x of type T1, which may make your job easier.

      If the lambda turns out to be unnecessary, you can always eta-reduce it away later.

    • If you are trying to produce a pair of type (T1, T2), you can always try to produce a value x of type T1 and a value y of type T2, then form the pair (x, y). Again, you've reduced the problem to one with smaller types.

  3. Once the types are as small as you can make them, look at the types of all the let-bound and lambda-bound variables in scope, and see how you can produce a value of the type you want. Typically you expect to use all arguments to all functions; if you don't, be sure you can explain why.

In many situations, especially when writing polymorphic functions, this design technique can reduce the construction of a complicated function down to just one or two choices. The types guide the construction of the program so that there are very few ways to write a function of the correct type---and usually only one way that is not obviously wrong.




回答3:


Best practice: use algebraic data types and take advantage of exhaustiveness checking from the pattern-match compiler. In particular,

  • Never match a wildcard pattern _ at top level.

  • Set compiler options so that a missing case in a pattern match is an error, not a warning.




回答4:


Don't follow principles, follow your nose. Keep functions short. Look for ways to reduce the amount of complexity in code, which often but not necessarily means the most concise code. Learn how to use the builtin higher order functions.

Refactor and reduce the code size of a function right after you've written it. This saves time because tomorrow you won't already have the problem & solution in your mind.




回答5:


Design pattern: let the compiler infer types for your functions, and make sure those types are exactly as general as you expect. If the types are more polymorphic or less polymorphic, figure out why.

For example, if you are writing a sort function in Haskell, expect

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

If your type is

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

or

[a] -> b

then something is horribly wrong.

Best practice: once you've confirmed with the compiler that the type is as you expect, put an explicit type signature for every top-level function. (Or if you are using ML or Caml, write an explicit interface.) Set compiler options so that values with missing signatures trigger an error.




回答6:


I'd answer with perhaps a bit vague principle: strive to make your code beautiful as the most important aspect. To quote David Gelernter:

Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defence against complexity.

and Brian Kernighan:

Controlling complexity is the essence of computer programming.

If you pursue this goal, it will lead you to write code that is easy to read and understand (which is very important), code that is split into small, compact parts with well defined purpose. It will lead you to learn how to express your thoughts in the best way in the particular language.

(All this doesn't apply just to functional languages, but writing beautiful code is so much easier in them.)




回答7:


Why Functional Programming Matters by John Hughes gives good motivation for why laziness and higher order (first class) functions provide a lot of what less functional languages are missing and supplement with design patterns.

In the context of Haskell, I thought the book Real World Haskell had some good and practical advice about idioms and abstraction and type classes and the like. The Typeclassopedia is also always useful. The core, very abstract type classes could be looked at as design patterns except they are enforced by the compiler/type system and part of the language (if you learn how to use them).

In the context of Lisp, Paul Graham wrote a book called On Lisp (available online) where he shows that functional languages are ideal to create a custom programming language and then write your program in that. So embedded domain specific languages themselves are a sort of design pattern.



来源:https://stackoverflow.com/questions/842026/principles-best-practices-and-design-patterns-for-functional-programming

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!