DEV Community

Cover image for Are You a Confused Programmer? Learn a Functional Language
Pan Chasinga
Pan Chasinga

Posted on • Updated on

Are You a Confused Programmer? Learn a Functional Language

Alt Text

Full disclosure: I'm an easily confused programmer. My mind does not work like a whiteboard genius. I was born an artist, best at scribbling than anything else. I taught myself to become a programmer in a visual language because I was partial to the graphics it created and the clacking of the keyboard. I was more an artist and a writer than a programmer. I get confused easily when I read complex code, so I almost always prefer reading human-friendly documentation and comments over reading source code when possible.

I spent the last few years since Recurse Center on a programmer's sabbatical in which I wander about trying out any interesting languages I could get my hands on. It's a personal journey to find my Thor's Hammer. Some I stuck to for quite a while, the other I ditched almost right after I dipped in. Because each language is designed differently for a distinct way of thinking, I know I have to keep looking for the tool that suits me best.

Over the years, even before the search, I've worked with C++, Java, Python, and Go. Of all these, Go suits me best and empowers me with the fastest, most natural way to work. I was at my peak that I wrote my first serious open-source library in just over a month. However, I've soon realized that it was still lacking for me (I continued to use Go because of its tremendous productivity boost), so when I was accepted into Recurse Center, I decided to dabble into the uncharted territory of functional programming. I first started off with Lisp and Clojure, then went on to learn Ocaml and Haskell, which were daunting but very refreshing. Before I could get far, I landed a job in Silicon Valley where I had to uproot and move to the other coast to write code in JavaScript and Python for the next 3 years.

It took me years to realize that as a confused programmer, I was not an outlier. Most of the programmers out there are. Let's admit it, most of us aren't born wired to program, and that should be okay because programming is a learning journey, not an acquired gift. During my years as an engineer, I had created countless bugs in my JavaScript and Python code (more so in JavaScript) because of the fast-paced nature, lack of mentorship, best practices, and emphasis on unit testing of the company I worked for, but mainly because I was confused. I tended to abstract things when it was not necessary because abstractions made me less confused when I think about my code. It was stressful when I had a deadline to meet and I was reduced to a coding version of dice-rolling--trying out code blindly and repeatedly run it until it works. Because Python and JavaScript permitted me to run code even when it's unlikely to be correct, the "ship it" startup mentality became "f*** it, let's commit" (engineers were even encouraged to push code and fix it as it breaks in front of the users in a move-fast-and-break-things style I guess).

Fast-forward to now, I'm a sole founder building my own product and running my own company at the same time. It is both relaxing and nerve-racking. It's relaxing because now I don't have to follow the 9-to-5 rule of someone else, commute when I don't have to (this is also true for many in the face of COVID-19 lockdown), and learn whatever I want to.

As I'm building the core product, a video checkout platform in Go and JavaScript, I'm also setting aside 10% of my time learning new languages like Crystal, Rust, and Haskell. I've more than once toyed with all these, but I never had the time (or the experience) to make them stick.

I dropped Crystal almost right away because of its Ruby-like syntax (it's also why I couldn't pick up Elixir, despite myself being productive in Erlang). I liked Rust, but I knew it would get in the way of me being productive long before I could get any ROI out of it. Then Haskell clicked. It was a mystique for me years ago when I first try to learn it, but years of programming in Ocaml, Erlang, and Lisp had built my skill up to the point that I'm beginning to enjoy it.

Functional languages (more so Haskell) have been infamously marked as only great for academicians and academic projects, like writing compilers. They have earned a bad name of being too "up there" to grok. Again, the human nature of evangelizing their own likings and throwing their pet-peeves under the bus has been at play. Most who don't grok functional programming are loud, and just like any negative news, they spread faster.

In my opinion, imperative and object-oriented languages like Ruby, Python, Java, and Go are confusing to the eyes and mind of an easily confused programmer like me. They are so confusing to me I'd normally need help from a serious intelligent IDE to be productive. For instance, in my Go codebase, I need to navigate everywhere to find variable and object references. It feels like a long film series with lots of episodes that once you pause and come back you'll need a recap to follow.

In functional programming, every bit of code is self-contained. It might be harder to understand what a certain expression is doing due to its high-level abstraction, but once it's understood it's final. There is very little magic in a functional language to confuse me, and with most state immutable I don't feel like creating new nuts and bolts just to make sure something persists.

For example, if there is only one feature of functional programming I can choose for all languages to have, it is pattern-matching. It gives programmers visuals of the data they are working with.


{- 
 - `h:t` reads `h` cons `t`
 - which means it is a list 
 - of at least an element
 - in front and the rest.
 -}

-- Get the first element in the list.
firstElement (h:t) = Just h
firstElement []    = Nothing


-- Sum all elements in the list.
sumList (h:t) = h + sumList t
sumList []    = 0

Enter fullscreen mode Exit fullscreen mode

In Go, my most productive language so far, the equivalent of would be:


// Get the first element in the list.
func firstElement(list []interface{}) interface{} {
    if len(list) == 0 {
        return nil
    }

    return list[0]
}

// Sum all int elements in the list.
func sumListOfInt(nums []int) int {
    sum := 0
    for _, num := range nums {
        sum += num
    }

        return sum
}

Enter fullscreen mode Exit fullscreen mode

The Go version is way more involved, especially when I'm the one reading.

The use of interface{} type in Go, as well as the deliberate sumListOfInt example function, should be noted here. It shows the weakness that comes with Go simplistic design compared to the sophisticate type system of Haskell, which I won't talk about here because it's off-topic.

I have no intention to start another flame war, hence I'm only comparing Haskell to the language I'm actively using and have a strong stake in. All I'm saying is contrary to the belief, functional programming is actually easier for an average programmer to reason with. It reads closer to English instruction as it doesn't require the programmer to be the register for the computer. To make this distinction super clear, take a look at a real-world task and how one might complete it in two different ways:

Get to the grocery store and buy pasta, tomato pesto, and sausage.

Imperative

From where you are, walk 20 yards until you see a junction, take a right and continue for another 0.5 miles. When you see a school to your right, continue for 10 yards and take the first crossing to the opposite side of the street. Walk another 2 blocks to the store.

When you're in the store, find pasta at the end of aisle #3, tomato pesto in aisle #4 at the middle, and head over the refrigerator to get the sausage.

...

Functional

Walk until you see a junction, take a right and walk until you see a school to the right, cross the street and continue until you see the store.

For all the aisles, get only the pasta and sauce, then go to the refrigerator to get the sausage.

...

Functional programming helps programmers avoid being too specific and focus on the high-level instructions (the WHAT instead of HOW), because the specificities are what humans are generally bad at (don't believe me? Can you recall how far you first had to walk before hitting the junction without going back to the grocery store simulation?)

If you are someone like me who gets confused when facing a big pile of code, try learning a functional language like Haskell. It might be a perfect map to your mental model.


If you'd like to try reading my thoughts on non-programming topics, you can subscribe to BETA School, my new blog.

Joe Chasinga Newsletter BETA School

Top comments (12)

Collapse
 
ghost profile image
Ghost

I never thought about it but something clicked, a few months I started to learn Rust after years with Python, I must emphasize the fact that Python is as "clear" as it can be, is like writing boring English, take normal English, get rid of synonyms, there you go, Python. So I was really scared about Rust, yet after not long I started to understand it, don't get me wrong, borrows and lifetimes take time to grasp and I'm still battling, but without noticing my code started to look more functional, in fact I learned what functional was after the fact, Rust is not purely functional but you can do it if you like AFAIK or you could do OOP if that is your jam. You made some interesting points, I'll pay more attention to it, thanks.

Collapse
 
pancy profile image
Pan Chasinga

Rust is great!

Collapse
 
ghost profile image
Ghost

indeed it is, I'm really enjoying it, and the web ecosystem is getting very good, very fast.

Thread Thread
 
pancy profile image
Pan Chasinga

Actix web rocks.

Collapse
 
kspeakman profile image
Kasey Speakman

I think I am a confused programmer too. I also tried many languages and ended up settling on F# as the one that seems the best balance between readable and concise. It is in the ML family with OCaml and Haskell, but it takes more after OCaml. I wrote about our back-to-basics approach here. I've seen style this described as Python with static typing. I like that. Additionally, I like being able to opt into some of the slightly more advanced patterns when the code benefits from being optimized for conciseness. Like URL routing or validation.

Collapse
 
pancy profile image
Pan Chasinga

I had strong-armed myself more than once into F# but the .NET orientedness has been quite hard to overcome as a Unix programmer. I also had a hard time adopting many cool languages like Clojure and Scala because they are tied to the JVM.
F# is a great usability improvement to Ocaml IMO.

Collapse
 
kspeakman profile image
Kasey Speakman

It's much better now since F# is well-supported on .NET Core. We run our F# stuff in production on linux machines in docker containers. I can sympathize though. I have done some initial explorations of Clojure, and digging into the JVM ecosystem is a learning curve. I imagine coming to .NET is similar.

Collapse
 
jkgan profile image
Gan Jun Kai

I strongly agree with your post. I'm using Elixir at my work (ya I like Ruby-like syntax) and using Rust in my free time. I have to say I love it. Pattern matching is fantastic. The expressiveness of these languages is just so pleasant to work with.

PS: Ruby also getting pattern matching in the latest version

Collapse
 
pancy profile image
Pan Chasinga

You're blessed to be working full-time in Elixir!

Collapse
 
evolveris profile image
Lia • Edited

This was a well-worded and interesting insight.

As a growing developer, the feeling that I get around is that I will not become a "serious" developer if I don't know my way OOP and the plethora of languages that are used for it - functional programming is never ever mentioned. Maybe that's something that only I am experiencing, and it's not something up for generalization. So hearing that other people simply don't find some languages as comfortable as they could be - is a refreshing thought. Makes me reconsider the way I'm approaching the things that I have/should learn.

After reading this and the comments, I think I might just give Haskell a try! 🤓

Collapse
 
pancy profile image
Pan Chasinga

Thank you for the thoughtful words.
In my opinion, there are many things that flourish because of the right timing and turns of events on top of their merits. Some things do get lost in time despite their tremendous values.

OOP was popularized by the advent of C++, but also because of the context around it (modernism) in which the general people view the world merely as objects and what they can do. Once that rolls downhill it's just hard to stop it in its track. If you look at the history of all programming languages you'll see that the line tracing from LISP to ML/Miranda seemed to have stopped bluntly, giving room to C++, Java, and eventually Python to flourish.

However I think from now on OOP will be on a decline, providing newer languages tend to ditch class inheritance entirely (Go and Rust, to name a few). The code and applications today are vastly more complex than before that more begin to see having mutable states everywhere in OOP are just beyond human programmers to control. A big popular proof that functional programming is growing on us lies in the most popular JavaScript library -- React.

What most people think or say isn't always correct. It might have been, but never age well. I sure hope you'll give any functional language a try.

Collapse
 
sobolevn profile image
Nikita Sobolev

If you like functional programming, static type checking, and Python then you should probably check out dry-python/returns library.

It is a collection of typed monads, transformers, and composition helpers. Works great with and without mypy.

Check it out!

GitHub logo dry-python / returns

Make your functions return something meaningful, typed, and safe!

Returns logo


Build Status codecov Documentation Status Python Version wemake-python-styleguide Checked with mypy


Make your functions return something meaningful, typed, and safe!

Features

  • Provides a bunch of primitives to write declarative business logic
  • Enforces better architecture
  • Fully typed with annotations and checked with mypy, PEP561 compatible
  • Has a bunch of helpers for better composition
  • Pythonic and pleasant to write and to read 🐍
  • Support functions and coroutines, framework agnostic
  • Easy to start: has lots of docs, tests, and tutorials

Installation

pip install returns

You might also want to configure mypy correctly and install our plugin to fix this existing issue:

# In setup.cfg or mypy.ini:
[mypy]
plugins =
  returns.contrib.mypy.decorator_plugin

We also recommend to use the same mypy settings we use.

Make sure you know how to get started, check out our docs!

Contents