Hi! I’m Catherine and I’m very fond of functional programming; I use the functional language on everyday basis and even do a bit of teaching.
Here in Typeable, we use Haskell as the main development language and while everyone else was disputing whether Haskell is ready for production, we just used it and regarded this as a competitive advantage. We would like to share our opinion which is based on this experience.
At present, functional programming is rather popular and many imperative languages are adopting some FP concepts such as lambda functions, partial application (currying), higher-order functions (map, filter, folding). Some of the adoptions blend seamlessly but some of them make the syntax look rather weird and foreign. Nevertheless, a programming paradigm is the approach existing in the programmer’s mind and generally not being a part of the language. To some extent, any language supports different paradigms and its structures allow developing software in various styles. The question of whether it makes sense to develop software in the functional style can’t be answered easily and each developer answers it based on their preferences, capabilities of the language, and other considerations. We believe that using the functional style in imperative languages or, better still, the functional language, especially in combination with static typing, will help to improve many aspects of the code, namely:
- The code will become more concise and expressive. Expressiveness can be defined as the number of ideas per code unit and, in general, functional languages, as high-level languages, also prove to be more expressive. For example, adjusting each element in an array or list is implemented by a functional one-liner (using map/foreach/whatever and an anonymous function), whereas the imperative style would require organizing a cycle, declaring a variable for the counter or iterator, and using explicit assignments. The difference in expressiveness is still more obvious in more complex examples.
- The code will be decomposed more naturally. The “divide-and-rule” principle has been used in software development for a long while and serves as the basic principle of software complexity management. I’m talking not about the algorithm design method but about a more general concept. For instance, even a simple program that reads the whole input text first, breaks it down into words, and performs some operations on each word can be decomposed into logical parts – the reading itself, breaking the text into words (for example, by spaces) and creating a structure used to store the words, traversing this structure including the words mapping, and results printout. Each of the actions can be implemented separately and in a rather abstract way so that they can be reused to solve other similar tasks. The code decomposition into smaller and more general parts makes the code much clearer (also for the author in the future), allows avoiding “copy-paste errors” and simplifies subsequent refactoring. I’m sure, a lot of developers occasionally had to dig their way through their own or someone else’s wallpapers of unstructured code which was written in a hurry, just to make the software work. It is difficult for the human brain to fix attention on a large number of entities at a time and solve one global problem at once (working memory), which is why it is quite natural for us to break problems down into smaller tasks, solve them individually and combine the result. In functional programming, these small tasks are expressed as minor auxiliary functions each doing its work which can be described in one short sentence. The final result is the composition of these functions. Of course, it is also possible to split the code into separate reusable segments in OOP and in a purely imperative low-level language such as C using well-known principles such as SOLID and GoF patterns, but if the language itself makes the developer think in terms of functions, the code is decomposed much more naturally.
- Side effects will be separated from pure functions. A pure function is a function in the mathematical sense; the result of its operation depends only on the input data. Evaluation of such a function involves nothing beyond the essential – variable values do not change, nothing is read or printed, no DB entries are made, and no requests to external services are issued. Indeed, you wouldn’t expect such operations, say, of trigonometric functions, would you? The major portion of data processing logic could be implemented using pure functions. Not all languages allow you to control the absence of side effects and check the function “purity”, but the functional approach by itself motivates to use pure functions working without any “surprises”.
- It will be easier to debug and test the code. This point stems from the previous two items: we have a number of small functions of which some are pure, i.e. we know that their result depends only on the input data. The code debugging becomes easier as it is only needed to check the result returned by the functions taken separately to understand the way they will work together. Unit tests for the “pure” logic of your application are written in the same unsophisticated way.
Further, I’d like to share my experience not directly related to writing programs in functional languages and tell you in what way the knowledge and application of FP turned out to be useful for me and can be of use to you.
- Learning an alternative paradigm is in itself useful for the brain. While you are mastering the functional style you will learn to give a new look at familiar things. Someone will find this way of thinking much more natural than the imperative one. We can argue at length about what is “useful” and “useless” in industrial programming, but, anyway, you cannot do without a clear mind, which needs training. Master the languages you don’t use in your work: LISP, Prolog, Haskell, Brainfuck, Piet. This will help you broaden your mind and can become a fascinating brain-teaser. With time, you will be able to use more elegant functional-style solutions even if you write programs in an imperative language.
- Functional languages are underpinned by a serious theory which can also become a part of your passions or even research, if you are eager to cast in your lot, to a greater or lesser degree, with computer science. It’s never too late to learn, especially when you have clear illustrations of how a pretty amusing theory can be used to solve everyday tasks. I’d have never thought that after graduating from the university I would watch lectures on the category theory (which my brain once failed to comprehend) and scrawl solutions for the course problems on paper just because it was of interest to me.
- In addition to broadening your mind, the interest in FP will also help you expand your social network. Probably, the “functional community” have earned the reputation of academic snobs who ask you to define “monad” before proceeding with the conversation. I also used to think this way until I was taken to my first functional meetups and conferences. I was a novice junior and didn’t know the definition of a monad but I never faced negative treatment. On the contrary, I got to know interesting people passionate about their work and eager to share experience, talk, and explain. Sure enough, any community consists of widely different individuals; you will like some of them very much and find some others toxic and repulsive, and this is absolutely normal. The fact that it will become possible for you to exchange ideas with those who view the development world from a slightly different perspective and have a different experience is of much greater importance.
- The least expected point for me was that jobs requiring Haskell knowledge were the easiest to find! As of today, I have a work experience of a little over five years, and in two companies out of my three places of employment I used Haskell, which was the most comfortable and painless employment experience. Moreover, I started off as a Haskell developer and I’ve never regretted this. My first job gave me basic skills of client-server architecture development and working with DB. We used to solve the same “down-to-earth” and “unscientific” tasks as the companies using more widespread languages. Most probably, your “Haskell developer” query on popular job sites will give you almost no responses. At best, you will find vacancies indicating that the knowledge of alternative paradigms will be an advantage. However, this doesn’t mean that such positions don’t exist. Vacancies regularly appear in social media. Yes, they are few and you need to know where to search, but good specialists in this area are also few in number. Surely, you won’t be hired right away and anywhere you like, but you will feel your employability much sooner than while searching for jobs requiring more popular languages. Probably, companies might be ready to invest in developers’ training in the discipline they require: if you cannot find a Haskell programmer, train them in-house!
Adoption of FP elements by popular industrial development languages such as Python, C++, Kotlin, Swift, and others confirms the usefulness and strong features of this approach. The functional style allows obtaining a more reliable code that is easier to decompose, generalize, and test, irrespective of the programming language. Of course, a functional language makes it possible to make full use of all of the above-mentioned advantages producing native structures with a high degree of expressiveness. Though there are a lot of functional languages, we believe that for the time being the ones using static typing are the most convenient and useful for development. They allow detecting most of the errors during compilation and expressing a part of the application logic at the type level.
As the final point, I’d like to encourage you to use alternative approaches and try them out in practice, even if this is useful merely in terms of your self-improvement.