DEV Community

Rob Sinkko
Rob Sinkko

Posted on

Learning Functional Programming

I would just like some language options on where to start my learning of Functional Programming.
I've been developing since the Commodore 64 days with a focus on C, C++, Java, and C#.
Thanks!

Top comments (39)

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

Keep in mind while learning FP, that (according to me at least) the most important guideline is to use pure functions as much as possible. That's how you get the maintainability benefits out of FP. Most of the rest of the functional programming patterns are just to support using pure functions. I have a more detailed post about that here. If you just use the patterns without pure functions its not going to get you much over other paradigms. Language suggestions:

Elm will force you to write pure functions. But it is a language/platform focused solely on (web) UI. If you have a project in mind targeting the web, this would be the route to go IMO. Download a high rated starter project so you don't have to get lost in the weeds setting up the build/dev environment. I also highly recommend Semantic UI (just the CSS) for GUI elements.

F# is my favorite. But since it has no distinction between pure and impure functions, it doesn't condition you as heavily into using pure functions. You can always fall back to imperative if a pure solution is elusive. I started with F#, and I feel like this led me to miss the point of FP for a while. (I was focusing on using functional patterns instead of writing pure functions.) But I think it is a great general-purpose FP language, because you can choose to go imperative in performance-critical parts. F# can call C# code and vice versa with no FFI.

OCaml is another option, and F# is based on it.

Haskell will also force you to use pure functions, but is much harder to break into (IMO) due to its complex type system and lots of operator symbols to learn. I'll mention Eta here too, as it is basically Haskell for the JVM.

Clojure is an interesting one. It's a Lisp dialect and dynamically typed so its FP flavoring is a bit different in general. I've heard it said that in Clojure (like Lisp) you write the code that writes the code to solve the problem.

Aside: I hate couching things in terms of purity and impurity... both types of functions are needed for any useful program. But historically those are the terms used in this context. A pure function is really just another name for a deterministic function.

Collapse
 
ben profile image
Ben Halpern

Great rundown, if you're interested in something new and interesting, check out Reason, and slightly more mature, Elixir language. Elixir is built on the Erlang VM, but has a lot of inspiration ideological inspiration from Ruby.

Collapse
 
kspeakman profile image
Kasey Speakman

Thanks. I knew I would forget some. :)

Note that Reason is just a Javascript-like syntax on top of OCaml. My pref would be to use the OCaml syntax, but dealer's choice.

Collapse
 
richjdsmith profile image
Rich Smith

Another +1 for Elixir here. It's fantastic!

Collapse
 
vasilvestre profile image
Valentin Silvestre

What's a "pure function"?

Collapse
 
tobias_salzmann profile image
Tobias Salzmann

It's a function that computes the same value, every time you call it with the same arguments, and depends only on those. The value can not depend on time or any mutable state outside of it.
It also can not have any side effects, like throwing exceptions or printing to the console.

This has a lot of benefits for reasonability, testability and compiler/runtime optimization, but can sometimes lead to code that's painfully explicit.

Thread Thread
 
vasilvestre profile image
Valentin Silvestre • Edited

I get it, each function have to do a precise task.

Thanks man :)

Thread Thread
 
idanarye profile image
Idan Arye

Not really - having each function do a precise task is a general good practice, not a quality of pure functions. A setter, for example, is an impure function that does a precise task.

Thread Thread
 
vasilvestre profile image
Valentin Silvestre

Ok, but you sometimes NEED to do impure function no ?
How could you not change the type of some variables ?

Ex :
You want to get array data to convert into object, you need to do an impure function no ?

Thread Thread
 
idanarye profile image
Idan Arye

Not really:

class Obj:
    def __init__(self, array):
        # ...


array = [1, 2, 3]
obj = Obj(array)

I converted the array to an object, but the function is still pure(or, more precisely, can be pure - I didn't write Obj.__init__'s body and Python does not guarantee function purity). We still have the original array - we did not change existing values, only returned new ones.

A better example will adding an element to an array:

def foo(array, value):
    array.append(value)


def bar(array, value):
    return array + [value]


array = [1, 2, 3]

foo(array, 4)
assert array == [1, 2, 3, 4]

array2 = bar(array, 5)
assert array == [1, 2, 3, 4]
assert array2 == [1, 2, 3, 4, 5]

foo is impure, because it changes an existing value. bar is pure, because it does not change an existing value - it creates a new one.

Thread Thread
 
vasilvestre profile image
Valentin Silvestre

Now I got it !

Last question, why do we have to do this ?

Thread Thread
 
malcolmkee profile image
Malcolm Kee

FP is not about eliminating side effect at all, because a software that does not has any side effect has no use at all. Instead, FP is about making as much area of your code to be pure function so that they are predictable and consistent, while allow only specific module to be impure, i.e. having side effect.

Thread Thread
 
vasilvestre profile image
Valentin Silvestre

.. So, pure function could also be a priority for OOP no ?

Thread Thread
 
kspeakman profile image
Kasey Speakman • Edited

I would think so, yes. You find that most Smalltalk-inspired OOP advocates tend to view sharing of data as a bad thing. Instead, data is private to an object, and you just tell the object what you want it to do (by sending it a message or invoking a method). The object then induces local mutations to itself. It's still not technically a pure function, but this flavor of OOP follows the spirit of not mutating a shared external state. Because that's what makes programs hard to change over time.

A pure function has additional benefits like thread safety.

Thread Thread
 
vasilvestre profile image
Valentin Silvestre

Ahah thread.. I'm doing PHP :(

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

The two conditions you need for a function to be pure.

  1. The return value of a function depends only on the input parameters.
  2. External values cannot be mutated (input values, globals, etc.).

Example violations.

let mutable x = 1

let addX value =
    value + x // violates #1

// x is not an input parameter.
// probably would still be ok if x was immutable.
type MyType = { mutable AnInt : int } 
let add x myType =
    // violates #2, mutates the input
    myType.AnInt <- myType.AnInt + x

Mutations to shared data are what makes code hard to follow and hard to fit in your head. This is sometimes called hard to "reason about".

The challenge of FP is figuring out how to get all significant decisions into pure functions. That way they are easy to test and reason about. Then push all side effects out to the impure edges of the application.

Thread Thread
 
idanarye profile image
Idan Arye

The input values cannot be mutated.

Just "the input values"?

Thread Thread
 
kspeakman profile image
Kasey Speakman • Edited

Yep. Technically, a mutation of a local, private variable (i.e. not passed by reference in or out), or using a out-of-scope (e.g. global) variable which doesn't change during program execution... both still allow a function to be pure. Such side effects do not affect the caller or any callees.

However, these are not great habits for FP learners to start with. I tend to only do local mutation for performance optimizations. Most of the time they aren't needed.

Thread Thread
 
idanarye profile image
Idan Arye

"The input values cannot be mutated" implies that global or closure variables can be mutated.

Thread Thread
 
kspeakman profile image
Kasey Speakman

Nice catch. I revised the wording.

Thread Thread
 
vasilvestre profile image
Valentin Silvestre

It seem to me ok but.. really hard and annoying.
Why do FP need pure function ?

Thread Thread
 
kspeakman profile image
Kasey Speakman

Modeling with pure functions is difficult at first, particularly if you know imperative programming well. In fact it took me a while to get used to it. But it eventually becomes familiar, and not any harder to do than procedural or OOP. Then you start to wish you had discovered it a lot sooner.

The payoff is well worth it. Primarily because pure functions have linear risk/cost to refactor. I don't know about you, but my experience previously has been that refactors to core code can have an unknown risk of breaking other things... but not so with pure functions. When you look at a function, what you see is what you get... no mysterious external, runtime state changes to account for. Refactorability is a benefit that pays dividends for many years to come. And as I said, once it becomes familiar its not even any more work (and perhaps less) than other methods. The main trade-off is the upfront cost of learning it.

Pure functions are also quite easy to test. If all your significant decisions are in pure functions, you don't really need mocks, fakes, and extensive test frameworks. You just need to vary the inputs and check the outputs. Testing logic is low-cost and easy. Testing side effects becomes integration testing (part of CI workflow, not in unit tests).

Collapse
 
bobbypriambodo profile image
Bobby Priambodo

Nice list, Kasey. As Ben already said, ReasonML is really nice to do functional programming in a C-like syntax.

I would also add to this, since Rob mentioned Java, Kotlin and Scala can also be a good choice on doing FP on the JVM. Kotlin particularly is nicer with less syntactic cruft than Scala, and it's gaining traction from Android community.

Collapse
 
tobias_salzmann profile image
Tobias Salzmann

Especially if coming from Java, I can recommend Scala.
There is a great course on coursera.org/learn/progfun1, taught by the creator of Scala, Martin Odersky.

Collapse
 
kentapolyglot profile image
Kenta Katsumata

I recommend Functional Programming in Scala

I read Japanese version of It and did many of exercises.

You can learn "Recursive function","Pure function","Algebraic data type","Monad", and many other concepts of functional programming by this book.

Some of exercises are difficult to solve. But many of them are very good exercises like puzzle.

After reading this book, I think you will be able to understand many of topics of functional programming.

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

If you're looking for practical experience that you can use in your current projects, then look towards the functional aspects of your current language. Functional programming is a paradigm, it does not define a language.

You are looking to using the high-level constructs like pure functions and high-order functoins. You want to learn about immutable data structures, recursion and things like lambdas and closures.

JavaScript, Python, and NodeJS, among those I know, all offer a good assortment of functional programming constructs. C++ does as well, but it's syntax can be a bit daunting. I'd likely start with Python since I've seen people use it's functional aspects to wonderful effect while coding (during interviews I've done).

Collapse
 
tobias_salzmann profile image
Tobias Salzmann

For me, it seems Python is an odd choice to learn functional programmming. I've recently picked it up for a project, and I do my best to use it in a functional way, but it keeps throwing obstacles. For example, the 2 primary data structures, lists and dictionaries are mutable.
There is a package called toolz that helps quite a lot, but compared to something like ramda for Javascript, it feels very shallow and without a clear concept.
It's main mode of failure also seems to be exceptions, which kind of makes it harder.
Why do you think it's a good starting point?

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

I said for practical experience. If you're already using Python on a project you can start learning functional constructs in your actual code.

Paradigms are only useful in combination with other paradigms as well, so it's good to learn how to use them together. In this case it's also helpful to learn the concepts when presented with a language that isn't strict about its constructs.

Exceptions are totally fine in the functional paradigm. Some languages choose to use Monads instead, but nothing about exceptions breaks the functional model. In my experience monads are more confusing, and less helpful than an implicit error model.

Thread Thread
 
tobias_salzmann profile image
Tobias Salzmann

I think we're talking about different things here. To be clear, I absolutely agree that functional programming concepts can be applied to any other language that does not feature it as one of their strongest paradigms. An generally, it's a good idea to do that to some degree, highly dependent on general language idioms.
In order to learn those concepts though I would recommend going for a language where those concepts are somewhere between important and fundamental. And that includes fundamental concepts like Monads, ADTs and referential transparency.

Whether exceptions are fine or not within FP really depends on the definition of both. I've seen monads being overused and annoying, but I've also seen them restoring maintainability for large codebases. For asynchronous code, they are very valuable.

Collapse
 
augustodossantosti profile image
Augusto Santos

I recommend Elixir for you. I started to learny it a few weeks ago and it's been a lot of fun.

The best book about this: amazon.com/Programming-Elixir-1-3-...

Collapse
 
eljayadobe profile image
Eljay-Adobe

There are lots of functional programming languages to choose from. The "best" one depends on your interests.

Since you have used C#, you have familiarity with .NET. I presume you have Visual Studio or Xamarin IDE on hand.

F# ought to be a good choice.

I've read a lot of F# books. The one I recommend to get your bearings with F# is The Book of F# by Dave Fancher.

In my opinion, it is a really good book for F# as a tutorial and hand-holding book. Different people learn in different ways, and this book fit very well with my learning style.

When I learned F#, I used Xamarin and Mono, on Macintosh. But I have experience with Visual Studio as well, and F# is definitely a first-class language in the .NET ecosystem.

Collapse
 
jj profile image
Juan Julián Merelo Guervós

You might want to give Perl6 a try. Although it's not purely functional, it does have the full range of functional structures. Plus you can do things procedurally if you want to. It's a great language, anyway.

Collapse
 
calvellido profile image
Juan Valencia

This could be a guided start (in Scala):

scala-exercises.org/fp_in_scala/ge...

There, the FP concepts are explained through Scala, so you can take the specific Scala syntax related too, if you need to.

Collapse
 
jvanbruegge profile image
Jan van Brügge

I dived heads first (no prior FP experience) into Haskell and I love it. "Learn you a Haskell" and "Real world Haskell" are great online resources to get you started.
The point I like the most about Haskell, is that it has a small core. It is not some syntax sugar abomination like C++ and more recently Javascript.
Every new extension added is still desugared to this small core. Plus, type classes are just amazing.

Collapse
 
courier10pt profile image
Bob van Hoove

I was going to suggest a Haskell MOOC, so I'll start by saying think Haskell is suitable for learning the core concepts :)

I would recommend Introduction to functional programming. The course is loosely based around Graham Hutton's book Programming in Haskell.

Once you've learned the core concepts it should be easy to switch to another language that may be applicable in your field of development.