Ideal Learning

Hauskin tapa oppia

On teaching functional programming concepts with less functional languages

Monads are on many developers’ radar

By just googling with keyword “monad” and seeing the number of entries one may realize that there is a great interest towards the concept. Having done some superficial research on the topic one can see that the interest is not only academic – there is a great deal of software developers looking for information on monads.

Software developers are mostly interested in the benefits of monads rather than the theory behind. There is loads of material available for those who are mostly interested in the theory behind, but not that much reading on the usage and benefits of monads. Strictly speaking monads have nothing to do with pure functional programming, but functional programming languages such as Haskell provides suitable abstractions for defining the monadic structures for programmers to use as stated in Gibbons J. (2013) Unifying Theories of Programming with Monads. In: Wolff B., Gaudel MC., Feliachi A. (eds) Unifying Theories of Programming. UTP 2012. Lecture Notes in Computer Science, vol 7681. Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-642-35705-3_2.

By reading the very first paragraphs of the above article we end up in a thought that one does not need monads for functional programming but may need some to write useful software. My intention is not to argue for or against whether monads are part of “realm of functional programming” or not.  Let’s relax our context a bit and say that monads are the only sensible way to construct real software by using a pure functional language.

I have not bumped into much research on the potential of the monad as a learning vehicle to motivate students to learn functional concepts in general. I would like to see this happen as I see a great potential for learning and teaching in monads and monadic constructs in general. Also, monads could be a key means to motivate students to rethink programming.    

Monads are here to stay

Monads are not at the heart of the numerous internet discussion, articles and blog posts by chance. Just by recognizing that there is not much software without (side) effects is a key to understanding the importance of monads. Monads have a huge potential in them. This is because monad is not only a theoretical construct but also a means to write effectful software in an easy to interpret way. The term interpretation in this context refers not only to the meaningful expression of the code but first and foremost to the readability of the code that would be less readable when written in an imperative language whether Java or something else.

Monad is not only a useful concept of computing science, but it could also be a great motivator for professionals for learning new ways of programming. According to the number of blog posts monads are being paid a great deal of attention to by software developers. Still, monads are not being utilized by educators to motivate students to learn new ways of thinking about programming.

Anyone who is aware of the history of programming (languages) knows that there is nothing new to lambda calculus, but I think the word new is allowed here, since to the vast majority of the students it appears “new”, this is especially true of those who have never been exposed to functional programming during their studies or have never hit the concepts at work. My perception is that this applies to most degree students at universities and other educational institutions as well as most professionals participating in training courses aimed at professionals. At least this applies to most parts of Finland.

JavaScript “monads” come in many shapes and sizes and that could be a problem

Functional programming professionals use monads all the time. The same cannot be said about JavaScript or Java programmers working on their daily programming tasks. There is a great deal of tutorials on how to implement monads in languages like JavaScript. Still, it is hard to imagine that one could come up with an easy to use monad implementation without a type system that would support the introduction of such concepts in the programming language.

To back up the statement above just google with “JavaScript monad” and check the number of entries. By comparing the lodash/fb based monad implementations to TypeScript based monad implementations one can see the benefit of having some kind of static type system in place when monads are being implemented by using external libraries. The intuition that builds up when recognizing that there is something “good” to the existence of the “compile time type system” (that makes the monad implementation more sensible) is “truthful”. Still, this feeling of “good” does not mean that one should learn monadic constructs by using languages like TypeScript or JavaScript.

Scala users are in a fine position and Java is a no go

Scala programmers are provided with somewhat toughened libraries for using monads. The typical Scala monads are somewhat close to their Haskell counterparts in many ways. Libraries such as scalaz has useful utilities for adding monadic computations to your programs. Even the Scala libraries which are considered high-end may have their shortcomings. For example, some libraries do not fully adhere to the monad laws which may be a source of difficult to find bugs.

The problem with Scala is that it allows one to do things in an imperative way with mutable objects.  Several people who have completed training courses such as Aalto University Scala MOOC at http://mooc.aalto.fi/ohjelmointi/scala_2019.html have also made the point that the course can be completed by not paying too much attention to the functional programming itself. This is a common problem with all hybrid languages such as Scala.

The anecdotal evidence of mine gathered during the last 4 years while teaching the concepts of functional programming to the software developers with imperative programming background shows that trying to fit functional concepts within an imperative language while learning the concepts of functional programming can be challenging, yet not impossible.  

Again, by doing a google search with keywords such as “learning monads”, we are likely to find quite a bit of discussion on how difficult they are. Very often the word “understanding” or phrases such as “how to understand monads” are being used in the discussion. The discourse reveals something about the nature of the problem. Rather than asking “how to use monads” the questions revolve around “how to understand monads”.

As an educator and software developer I find this discussion not only interesting, but also highly rewarding as there is a great challenge in alleviating the obvious pain there is in learning monad like constructs and their usage while solving real life programming puzzles. 

Teaching trials with Java

During the last 10 years many programming languages have picked up many features that could be called “functional” such as Java’s Stream APIs accompanied with FunctionalInterface and Kotlin’s functions as first-class citizens. The challenges in understanding monadic constructs is likely not related to the lack of intellectual capability or being a lazy but to the programming language in question. It is simply a question of trying to fit a square peg into a round hole.

My experiments of teaching functional with Java have ended up with a conceptual mess. Having discussed with the students during and after the training courses I have found out that students’ own perceptions of what they have learnt differ from person to person. Some have found the subject totally useless whereas some have found it “interesting” or “maybe useful in the future”.

Starting a lecture with “it’s all about immutability…” and then ending up explaining why in Java one can refer to and manipulate data outside the scope of an anonymous function has been one of the greatest challenges in my career so far. Mixing functional and imperative in such a way may be a challenge not only to me, but also to many colleagues out there, too. In real life we do it for sure – there are beautiful Scala stacks with pure and impure sides separated with very little mutable data, but when it comes to the learning phase, the Scala approach may be too much, too soon.  

Based on my experiences Java is a bad language for teaching or learning functional programming. Not only because monads are impossible to represent but also because (mutable) objects are “on the way”.

There is a great deal of texts out there explaining how useful it would be to be able to write pure functions with Java and in the next turn let you shoot in your foot every now and then. It is partly because of the language design and therefore there is no easy way out, especially in the case of Java.  

Ramda and JavaScript to the rescue

Java is a dead end but those who have successfully applied functional constructs by using libraries such as Ramda (JavaScript) have found functional programming not only useful, but also interesting. In Ramda all functions are curried by default. I have used Ramda as a tool for demonstrating data transformation/manipulation and some students have found this very motivating as they can use a familiar language to trial new concepts.

Whether it is Ramda or lodash/fp or something else, my recommendation is to use JavaScript rather than Java to teach functional programming, no matter how many books on “how to write functional Java” there might be. The Ramda library pays attention to the immutability, too. With the tools like Ramda one gets two in one:  curried functions and emphasis on immutability over mutability. This is a much better starting point compared to experimenting with Java. Kotlin is also more suitable for functional experiments if Scala and Haskell are out of question.

The reason for recommending JavaScript’s Ramda library over Java is that many universities and educational institutions have no Haskell courses available, and if there are any they are often offered as “auxiliary” courses rather than being part of the elementary programming curriculum.

I am currently involved with a teaching experiment where JavaScript is used as a means to teach some functional concepts. It is interesting to see how people perceive their functional programming skills being developed during the course. For all professional self-learners the message is the same as usual, learn Haskell if possible. In addition to learning lambdas, you will get to learn what type systems are all about.

As Java is an “everything is mutable by default” type of language there is a big problem in trying to explain the students that the immutability is at the very heart of what we are trying to achieve. Having explained the concept of an anonymous function in the concept of Java and compared the explanation to its functional language counterparts I have ended up with mixed feelings.  

Functional features, pure functional programming and functional design (patterns)

Educators could draw a stricter line between writing software with a language with “functional features” and writing software with “pure functional language”. In many articles and blog posts that refer to monads and functional programming, the term functional programming is often left undefined. Functional programming “can be“ anything from using a map within an otherwise imperative code to using only pure functional concepts. This is especially challenging to the readers who have not hit both ends of the functional programming continuum and therefore have no means to put the content in context. It maybe useful overdo a bit when it comes to drawing the line between pure functional and the rest. It is a simplification but can be useful when learning the basics.

One challenge a teacher may face is to separate the above two terms “functional features” and “pure functional programming from “functional design practices” such as separating pure parts of the software from the impure parts in hybrid designs written in languages such as Scala. Isolating side-effects is the key learning point here.  

If learners are left without a context, they are likely to mix the concepts. One can separate the three by only getting familiar with both ends of the programming continuum. By defining programming paradigms as a simplistic continuum from functional to imperative does not respect the complex nature of modern programming practices but may still be the most pragmatic vehicle for classifying languages.

I have used the continuum heavily to highlight the differences of programming languages and found it useful in building elementary understanding for concepts such as “impure parts of the program” and “pure parts of the program”.

Summa summarum

It’s never easy.

Selma is looking for a monad.

Piditkö artikkelista? Suosittele sitä muillekin!

Facebook