Functional Programming Is Not Popular Because It Is Weird

by Malte Skarupke

I’ve seen people be genuinely puzzled about why functional programming is not more popular. For example I’m currently reading “Out of the Tar Pit” where after arguing for functional programming the authors say

Still, the fact remains that such arguments have been insufficient to result in widespread adoption of functional programming. We must therefore conclude that the main weakness of functional programming is the flip side of its main strength – namely that problems arise when (as is often the case) the system to be built must maintain state of some kind.

I think the reason for the lack of popularity is much simpler: Writing functional code is often backwards and can feel more like solving puzzles than like explaining a process to the computer. In functional languages I often know what I want to say, but it feels like I have to solve a puzzle in order to express it to the language. Functional programming is just a bit too weird.

To talk about functional programming let’s bake a cake. Taking a recipe from here, this is how you bake an imperative cake:

  1. Preheat oven to 175 degrees C. Grease and flour 2 – 8 inch round pans. In a small bowl, whisk together flour, baking soda and salt; set aside.
  2. In a large bowl, cream butter, white sugar and brown sugar until light and fluffy. Beat in eggs, one at a time. Mix in the bananas. Add flour mixture alternately with the buttermilk to the creamed mixture. Stir in chopped walnuts. Pour batter into the prepared pans.
  3. Bake in the preheated oven for 30 minutes. Remove from oven, and place on a damp tea towel to cool.

I’d take some issue with the numbering there (clearly every step is actually several steps) but let’s see how we bake a functional cake.

  1. A cake is a hot cake that has been cooled on a damp tea towel, where a hot cake is a prepared cake that has been baked in a preheated oven for 30 minutes.
  2. A preheated oven is an oven that has been heated to 175 degrees C.
  3. A prepared cake is batter that has been poured into prepared pans, where batter is mixture that has chopped walnuts stirred in. Where mixture is butter, white sugar and brown sugar that has been creamed in a large bowl until light and fluffy…

Ah screw it I can’t finish this. I don’t know how to translate the steps without mutable state. I can either lose the ordering or I can say “then mix in the bananas,” thus modifying the existing state. Anyone want to try finishing this translation in the comments? I’d be interested in a version that uses monads and one that doesn’t use monads.

Imperative languages have this huge benefit of having implicit state. Both humans and machines are really good at implicit state attached to time. When reading the cake recipe, you know that after finishing the first instruction the oven is preheated, the pans are greased and we have mixed a batter. This doesn’t have to be explicitly stated. We have the instructions and we know what the resulting state would be of performing the instructions. Nobody is confused by the imperative recipe. If I was able to actually finish writing the functional recipe and if I showed it to my mom, she would be very confused by it. (at least the version that doesn’t use monads would be very confusing. Maybe a version using monads wouldn’t be as confusing)

I’m writing this blog post because I ran into a related problem recently. C++ templates are accidentally a functional language. When this was realized that problem wasn’t fixed, but instead the C++ designers doubled down on functional templates which can make it terribly annoying to convert code to generic code. Here’s something I wrote recently for a parser: (I know it’s stupid to write your own parser, but the old tools like yacc or bison are bad, and when I tried to use boost spirit I ran into a few problems that took way too long to figure out, until eventually I decided to just write my own)

ParseResult<V> VParser::parse_impl(ParseState state)
{
    ParseResult<A> a = a_parser.parse(state);
    if (ParseSuccess<A> * success = a.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    ParseResult<B> b = b_parser.parse(state);
    if (ParseSuccess<B> * success = b.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    ParseResult<C> c = c_parser.parse(state);
    if (ParseSuccess<C> * success = c.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    ParseResult<D> d = d_parser.parse(state);
    if (ParseSuccess<D> * success = d.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    return select_parse_error(*a.get_error(), *b.get_error(), *c.get_error(), *d.get_error());
}

This function parses a variant type called “V” by trying to parse the types A, B, C and D. They have better names in the real code but those names are not important. There is some obvious repetition here: This calls exactly the same code for four different parsers. C++ doesn’t really support the monad pattern, but I could make this reusable by writing a loop that iterates over all four, trying them in order:

template<typename Variant, typename... Types>
ParseResult<Variant> parse_variant(ParseState state, Parser<Types> &... parsers)
{
    boost::optional<ParseError> error;
    template<typename T>
    for (Parser<T> & parser : parsers)
    {
        ParseResult<T> result = parser.parse(state);
        if (ParseSuccess<T> * success = result.get_success())
            return ParseSuccess<Variant>{{std::move(success->value)}, success->new_state};
        else
            error = select_parse_error(error, *result.get_error());
    }
    return *error;
}
ParseResult<V> VParser::parse_impl(ParseState state)
{
    return parse_variant<V>(state, a_parser, b_parser, c_parser, d_parser);
}

There is some overhead here because I have to select one of the error messages to return, but overall this is a pretty straight forward transition to do. Except you can’t do this in C++. As soon as templates are involved you have to think more functional. Here is my solution:

template<typename Variant, typename First>
ParseResult<Variant> parse_variant(ParseState state, Parser<First> & first_parser)
{
    ParseResult<First> result = first_parser.parse(state);
    if (ParseSuccess<First> * success = result.get_success())
        return ParseSuccess<Variant>{{std::move(success->value)}, success->new_state};
    else
        return *result.get_error();
}
template<typename Variant, typename First, typename... More>
ParseResult<Variant> parse_variant(ParseState state, Parser<First> & first_parser, Parser<More> &... more_parsers)
{
    ParseResult<First> result = first_parser.parse(state);
    if (ParseSuccess<First> * success = result.get_success())
        return ParseSuccess<Variant>{{std::move(success->value)}, success->new_state};
    else
    {
        ParseResult<Variant> more_result = parse_variant<Variant>(state, more_parsers...);
        if (ParseSuccess<Variant> * more_success = more_result.get_success())
            return std::move(*more_success);
        else
            return select_parse_error(*result.get_error(), *more_result.get_error());
    }
}
ParseResult<V> VParser::parse_impl(ParseState state)
{
    return parse_variant<V>(state, a_parser, b_parser, c_parser, d_parser);
}

I am actually very happy with this. Sure it’s harder to read because the iteration is hidden in a recursion, but you should have seen what I had before I came across this solution: I had a struct with a std::tuple<std::reference_wrapper<Parser<T>>…> member. If you’ve ever worked with a variadic sized std::tuple, you know that that alone turns any code into a puzzle.

In any case the point is this: I had some straight imperative code that was doing the same thing several times. In order to make it generic I couldn’t just introduce a loop around the repeated code, but I had to completely change the control flow. There is too much puzzle solving here. In fact I didn’t solve this the first time I tried. In my first attempt I ended up with something far too complicated and then just left the code in the original form. Only after coming back to the problem a few days later did I come up with the simple solution above. Making code generic shouldn’t be this complicated. The work here is not trying to figure out what to do, but it’s trying to figure out how to satisfy a system.

I get that too often in functional languages. I know C++ templates are a bad functional language, but even in good functional languages I spend too much time trying to figure out how to say things as opposed to figuring out what to say.

Now all that being said do I think that functional programming is a bad thing? Not at all! The benefits of functional programming are real and valuable. Everyone should learn at least one functional programming language and try to apply what they learned in other languages. But if functional programming languages want to become popular, they have to be less about puzzle solving.