If you are a programmer working on popular languages such as Python or Java, you are likely to have read articles about "functional programming". These articles can give you the idea that learning functional programming improves your skills as a programmer. I share this opinion.
This article tries to help people who have read about functional programming figure out how to proceed.
Note that this article expresses personal opinion. Particularly, I am not an expert in this topic:
Shortly after writing this, I was shown:
In which there is no such thing as a functional programming language
I agree with most of that the article explains. I might extend this article with some similar ideas, but for the moment, I recommend reading that carefully before reading the rest of this article.
The Wikipedia article on functional programming is a great place to get started.
The article describes a few concepts related to functional programming. I consider the following two the pillars of functional programming:
These concepts can be applied in most popular programming languages.
For example, in Python:
def hello():
print("hello")
def twice(f):
f()
f()
twice is a higher order function because it takes a function as an argument. Functions are first-class functions because you can use hello as a value:
>>> twice(hello) hello hello
Similarly, you can write pure functions in almost any language.
When you have first-class functions, you can define some higher-order functions that generalize some common code. Three very common higher-order functions are:
(For example, folding with the sum operator and an initial value of 0, sums the elements of a list.)
Note that you can implement many list manipulations by composing filters, maps, and folds with different functions. (And by adding more higher-order functions, you can implement more list manipulations.)
Also, you can manipulate other data structures with equivalent or other higher-order functions.
Implementing code using higher-order functions and pure functions already has some interesting benefits.
You can use these concepts in most popular programming languages. (Most popular languages also provide higher-order functions such as filters, maps, and folds.)
So you can get started with functional programming by using the programming languages you already know:
Writing code using these concepts often leads to:
Therefore, many programming languages provide features that make functional programming more straightforward, or features enabled by functional programming. Languages providing features related to functional programming are commonly named "functional programming languages".
Although you can use functional programming with non-functional programming languages, this can often lead to:
Higher-order functions often have complex type requirements. For example, to filter a list of a given type, you must pass a function that takes a single argument of that type and returns a boolean. If the arguments do not have the correct types, then the code does not work correctly.
In languages with dynamic types, the program fails at runtime. In languages with static types, you frequently must specify the types, and higher-order functions often require complex types involving different function types.
Functional programming languages frequently:
Because functional programs often use more complex types, functional programming languages often have more powerful type systems than non-functional programming languages.
Derived from those properties, functional programming languages result in the "if it compiles, it works *correctly*" phenomenon. This phenomenon helps avoid incorrect programs.
Functional programming practitioners often recommend Haskell as a functional programming language.
According to the Wikipedia, "Haskell is a general-purpose, statically-typed, purely functional programming language with type inference and lazy evaluation". Also, Haskell was designed by a committee whose purpose was "to consolidate existing functional languages into a common one to serve as a basis for future research in functional-language design".
However, Haskell's benefits frequently also are negative for learning.
When writing Haskell code for learning, you can likely stumble into issues not present in languages that use eager evaluation.
Also, Haskell syntax is very terse, which leads to Haskell compilers not providing clear error messages. For example:
$ ghci
> let sum a b = a + b
> sum 2 2
4
> sum 2 2 2
<interactive>:3:1: error:
• Non type-variable argument in the constraint: Num (t1 -> t2)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall {t1} {t2}. (Num t1, Num (t1 -> t2)) => t2
In complex programs, programmers new to Haskell might have trouble identifying that a function has been called with an extra argument from that error message.
Personally, Haskell is my favorite functional programming language. However, I learned Haskell after learning (with teachers and support from others) other functional programming languages. I think that Haskell is ideal to learn the most powerful concepts in functional programming, but it is not as ideal as a first functional programming language.
(Note that these recommendations come from someone who only has implemented about 50 Project Euler problems in Haskell, and has experimented on and off with the language, but not been paid for it.)
Many programmers like Lisp and languages in the Lisp family, such as Scheme or Clojure. Lisp programmers often recommend Lisp to learn functional programming.
Lisp is a very minimalistic, yet infinitely flexible language. Lisp is extensible, so you can add most programming language features to Lisp, including functional programming features.
Therefore, you can do functional programming in Lisp, and also benefit from all other Lisp features.
However, languages in the Lisp family tend to not have static typing and associated features, thus do not frequently exhibit the "if it compiles, it works *correctly*" phenomenon.
Lisp has one of the simplest syntaxes of any programming language. The simple syntax of Lisp is directly tied to its power. Many favor the Lisp syntax and argue that the syntax makes Lisp better for learning programming. Personally, I find the Lisp syntax hard to read and write, and likely an additional difficulty on top of learning functional programming.
I recommend learning Lisp because it is a unique programming language that can teach you many programming language concepts that are not present in many other languages. However, I do not recommend Lisp for learning functional programming (unless you already know Lisp).
(Note that these recommendations come from someone who has some formal training on Lisp but only uses Lisp infrequently [as a recent Emacs user].)
ML is a language that appeared in 1973. Since then, three dialects have become the most popular implementations of ML:
Specifically, OCaml and F# have very strong ecosystems (OCaml because it is a popular and mature language, F# because as part of the .NET platform, it can use many .NET libraries and tools).
Haskell is inspired by ML, but many of the Haskell features discussed above are not present in the ML languages:
For example, compare the following snippet of OCaml to the previous error message example from Haskell:
$ utop # utop is a friendlier OCaml REPL
# let sum a b = a + b ;;
val sum : int -> int -> int = <fun>
# sum 2 2 ;;
- : int = 4
# sum 2 2 2 ;;
Error: This function has type int -> int -> int
It is applied to too many arguments; maybe you forgot a `;'.
In my opinion, OCaml and F# are better languages for the initial learning of functional programming than Haskell. After learning an ML, you are likely more prepared to learn Haskell and more sophisticated functional programming.
(Note that those recommendations come from someone who only has experimented with OCaml and F#, and learned SML formally.)