(I'm assuming that as a 5yo, you know at least basic programming concepts)

The core and most important concept of functional programming is that of a pure function. A function is pure when its return value depends only on its input arguments, and the function does not cause side effects observable elsewhere in the system. For example, a function add(a, b) { return a+b; } is a pure function. Functional programming is fundamentally about building as much of your program as you can out of such pure functions.

Pure functions have a number of benefits:

  • They are easier to read and understand than "regular" functions, because their output depends only on the input arguments.
  • They are easily testable, as there's no extra state to prepare, just input arguments.
  • They compose well, because there's no state to manage.
  • They parallelize extremely well, because there's no state to cause bugs or locking.

Trying to build a program out of pure functions drives you towards a different style than imperative/OOP approach: code written in functional style tends to be built out of transformations of data.

Think of e.g. washing the dishes. You usually wash them, then dry them, then stack them together. A functional code implementing that would look like:

function clean_dishes(dishes) {
  const washed = wash(dishes);
  const dried = dry(washed);
  const stacked = stack(dried);
  return stacked;
}

or, in short:

function wash_dishes(dishes) {
  return stack(dry(wash(dishes)));
}

This is the core concept of functional programming. Of course, you can't write your entire program using just pure functions - after all, reading data from user or printing it out are those unpure "side effects". But you can write most of your program this way.

There are more ideas that work well with this style, that you'll frequently find in functional languages.

  • Closures and higher-order functions. Functional programming is really convenient only when functions are "first-class objects" - i.e. can be created at runtime and passed around like any other data type. This enables "higher-order functions", i.e. functions taking functions as argument, which opens up a lot of nice abstractions. "Mapping", "reducing", "zipping", "currying", etc. all fall under this category.
  • Immutable data. Many languages will force functional style on you by disallowing in-place modifications of existing data. E.g. appending an item to a list will return a new list instead of modifying the existing one. With some trickery in language implementation, this isn't as inefficient as it sounds.
  • Advanced type systems. Functional programming is fundamentally an implementation of mathematical thinking, and mathematicians like type systems and category theory :). Note that static typing is not required for functional style; Lisp essentially invented functional programming, and to this day it's a family of dynamicly-typed languages.
 
 

FP is just using types (data structures) and functions to solve problems. Like anything, it requires practice to do well.

If you understand procedural programming, you can start with that understanding. But where procedures encourage you to pass data into another procedure to be modified, functions expect input data (which will not be modified) and return output data. Much like electronic circuits have dedicated input and output pins/leads. FP also adds several capabilities over procedural.

  • Immutability by default
  • Pass functions as arguments in the same way you pass data as arguments
  • Call a function with an incomplete parameter list (partial application)
    • This creates a new function that only needs the parameters you didn't provide
  • Sum types, which allow you to say "either this data structure OR that data structure but not both".
  • Pattern matching, especially for sum types, allows you to choose different behavior (functions) for different kinds of inputs.

Versus OO, the primary difference is that OO objects bind data and behavior together. Using the traditional OO organizational technique of inheritance, this can lead to hard-to-resolve conflicts of behavior or data structure. This in turn leads to all manner of OO guiding principles including SOLID. However, FP keeps data and behavior (functions) separate. So you can compose data types with other data types and functions with other functions without much fuss. Types act as a contract between functions. And functions simply transform input into output.

Up to now I have assumed pure transformation functions (only converting input to output, no side effects such as printing to screen), as these are the easiest to understand and test in isolation. You want as much of your program as possible to be made of these. But at some point, you have to perform side effects. This is best done "at the edges" of your program. Personally I like to declare side effects as data (whatever data is needed to perform it), so the inner core of my app can return the side effect as plain data. Then I have an effect function at the edge which takes the declared side effect and actually performs it.

Here is a relevant video.

 

I read somewhere that functional programming was easier for young kids to understand than imperative. Maybe you should ask for it to be explained like you're 20.

I'm not sure I think functionally enough to help achieve that state. I would say that the main gate is for your function calls to take arguments, don't modify them and chain those functions.

D has a keyword, pure, to help enforce these rules. But it defaults to what is referred to as weakly pure.

 

I read somewhere that functional programming was easier for young kids to understand than imperative. Maybe you should ask for it to be explained like you're 20.

This is true in so far as this is how math works, and people learn that in school. Learning imperative programming involves understanding things like "function" of "what X = 2 means" differently than in math classes, whereas in functional programming, those concepts are behave similar to math.

 

Your hands can do things right? And your feet and your tummy do things, and so does your head. If we were talking about OOP, all of the different parts of your body and the behaviors they perform would all be apart of the object that is you. If someone needed you to do something with just your hands, they would need to create an entire you to do it.

With functional programming, your head and hands and feet and tummy are all separate functions that manipulate all of the different types. They don't have to be coupled to you anymore. If someone needed more than 2 of your hands, they would just need to invoke multiple calls to your hand functions. They wouldn't need to create two or more of you in order to use your hands. They do all the same stuff, but they can all be there own separate parts.

A less like I'm 5 explanation: functional programming languages can have strong typing systems, but those types can't expose behaviors, nor are they tied to any specific behavior or contract. There's no such thing as interfaces or class hierarchies.

Instead, when you create a type, you would write functions that can be used to manipulate that type. Those functions can be chained with other function calls to do other things.

Check out Elm if you're interested in learning functional programming. It compiles into JavaScript and can be used to create web applications. Compiler messages are super helpful, and the community is awesome.

Imagine three people sitting in a room, lets call them Anna, Brad and Carol.

In object oriented programming, Anna has a paper with cats written on it, and Brad has a paper with are cool written on it. Then Carol comes and asks Brad what do you think?. Brad asks Anna what do you have?, Anna looks at her paper and answers cats. Brad then looks at his paper and answers to Carol Cats are cool.

In functional programming, Carol comes and asks What do you think? then Anna produces a piece of paper, writes cats on it and passes it to Brad. Brad looks at the paper and writes are cool next to cats. Then they hand out the paper to Carol and she reads cats are cool.

img

I can't take credit for the image, but it seemed to helped me to remember how to use each 😉

A couple of resources which might help:

A practical introduction to functional programming

Classic DEV Post from Jan 22

4 things that I always manually test

Automation certainly makes a lot of things easier, like catching a text input without an associated label, but here are a few things that always do manually to ensure a positive user experience.

I'm a learner, loves joe editor.