Issue #40: Functional programming

Every fifth week I make a special issue covering particular topic of Elm. You can find them all under the special tag. Elm is my first foray into the world of functional programming (Python's functools don't count), and in the absence of constant practice I decided to start this newsletter as a way for me to keep learning about it.

As I keep reading articles, news, blog posts, and discussions, I stumble upon some terms that I make me open Wikipedia, StackOverflow, Google, and sometimes more scientific resources, that I decided to make an exception and do this special issue on functional programming, some of the most common terms that a newbie (or a person with OOP background) would certainly encounter. This is a way for me to learn the difference between monads and monoids, function and functor, and other concepts. I must say though that this is not an introduction to functional programming (there is a great guide already), or an extensive guide on the topic, but rather a short hitchhiker's guide into the basic fp terms and concepts illustrated in Elm. I will also reference some historical data that I found interesting. Now let's dive in...

Often times when I stumble upon some term of pattern in Elm and research it, I keep seeing references to Math and lambda (λ) calculus. This is important because many concepts in functional programming come directly from mathematics.

Let me start with pure functions which I'm sure many use in imperative programming, but very few self-taught developers know about them. With the introduction of hooks in React, many learned the concept of pure functions. Pure function in programming is a computational analogue of a mathematical function. Pure functions return the same value for the same arguments, and evaluation of a pure function doesn't produce any side effects. Take a simple math function like f(x) = x², it always returns the same result for the same input, it doesn't produce any side effects, ie. no mutable references, no global variables.

Pure λ-calculus doesn't have a concept of named constants, although there are interesting workarounds. An expression f.N) M (which means "use M to call function f inside N) can be rewritten as let f = M in N. After getting through the first shock of realizing you don't have variables in Elm, one learns about the similar concept, let expressions:

let
    endpoint =
        "http://example.com/users?q=" ++ searchTerm
in
Http.get
    { url = endpoint
    , expect =
        Http.expectJson (RemoteData.fromResult >> UsersListReceived) usersListDecoder
    }

Looks exactly like in the math notion, isn't it? And the more I learn about these, the more excited I become.

Higher-order functions is another concept that excites me (yeah, talking about things that excite me). Why, you would ask? It's available in pretty much every programming language out there. What I didn't know however before starting with Elm, is that the concept comes from mathematics too when for example, using differential equations.  Here's a refresher for higher-order function in Elm (using the same example used in Wikipedia in the above link):

plusThree : number -> number
plusThree x = x + 3

twice : (number -> number) -> number -> number
twice f x = f(f(x))

g : number -> number
g x = twice plusThree x

And when running g 7, we get the 13 as the result. Similarly the concept of anonymous functions also comes from λ-calculus. It's like a whole new world was opening in front of my eyes as I was connecting things I already knew but didn't know the names to programming patterns.

I have never heard the term currying before learning about functional programming. It is mentioned quite frequently in blog posts, articles, and videos, and the concept is so natural when applied in Elm, Elixir, or other functional languages, but so foreign in imperative languages. By the way, currying is a mathematical concept named after Haskell Curry.

In simple terms, currying is the process of converting a function that takes N number of arguments to a sequence of functions that each take just a single argument. Suppose we have a function that receives two arguments. If you were to pass only one argument, Elm would return another function which accepts only one argument.

greet : String -> String -> String
greet greeting name = greeting ++ ", " ++ name

If we run this function in repl and pass it "Hello", we would get the following:

> greet "Hello"
<function> : String -> String
A function that accepts String and returns a String

So we have just reduced a function that accepted multiple arguments to a function accepting just a single argument. This example is artificially simple and useless, but the currying is very handy, for example, in a code like this:

blueSquare : Html.Attribute
blueSquare =
    createStyle
    |> backgroundColor "blue"
    |> height "200px"
    |> width "200px"
    |> done
    |> style

An example I took from Alexander's post explaining that concept. Here, instead of writing blueSquare = createStyle... followed by a lot of parentheses and parameters, we pass one argument to a function which returns a function accepting N - 1 arguments, to which we pass another argument. And so on. I suggest you read that post for a full explanation with good examples.

If you've used shell before, you're likely aware of the | operator. It's a pipe which allows you to redirect output of one program to the input of another. In Elm you learn the concept of function chains early one. In fact, as you read this text you've already seen it in practice in the previous paragraph. Elm uses |> construct pass the result of the function to the next function as its last argument. Not only that, but Elm supports sending data the other way around too, using <| . Here's a simple example of that operator in action:

String.concat ["h" "e" "l" "l" "o"]
    |> String.toUpper
    |> String.reverse

And if you've been decoding JSON, mostly likely you're using Json.Decode.Pipeline which allows the following:

userDecoder : Decoder User
userDecoder =
    field "data"
        (Decode.succeed User
            |> required "id" int
            |> required "fullName" string
            |> required "username" string)

I think the closest thing to a pipeline operator in object-oriented languages is a builder pattern.

On to monads. And this is where things become a little bit tricky for the format of this email. You see, in order to explain what a monad is, one needs to write the same amount of text as I've already written. Luckily Luca Mugnaini and James Carlson have both written lengthy blog posts on that exact topic, and of course examples include Elm come. Here's Functors, Applicatives, and Mondads in Pictures by Luca, and Monads in Elm by James. If you want to explore this topic deep enough, I suggest to look at a thirteen-part series by Eric Lippert.

For the past five years I've been thinking about getting back into the university to study math. It's hard to do so when you have two small children, mortgage, you're running a startup, and also trying to stay sane. And while Elm is not helping me with math directly, the more I learn about functional programming, the more I dive into the math.

Hope you learned something new from here. I certainly did while preparing this essay. And I'll finish this one with a quote from Danica McKellar:

One of the most amazing things about mathematics is the people who do math aren't usually interested in application, because mathematics itself is truly a beautiful art form. It's structures and patterns, and that's what we love, and that's what we get off on.
Show Comments