Over the past week, or so I’ve been making an effort to really get a feel for functional programming by implementing a small program, that would normally take very little effort using OOP. The program in question is a simple program that determines gas consumption for two virtual cars. One car being a truck and another being a sedan.
When I first started this program, I knew how to use Haskell Type classes , as well as some list comprehensions, pattern mapping. Basically tools that would allow me to build a real program. Not an example program or implement some subset of functionality.
I feel as though the programs and examples I’ve found online as well as the learning material almost always suspiciously leave out project exercises that would help take you to the next level. Instead the focus is entirely on what the constructs of the language, but do not necessarily show you should think about using them.
Its still early days for me, so the way I went about conceptualizing this project may not be the best. I found that my thinking differed very much from traditional OOP, but found itself with a cleaner way to achieve what dependency injection systems do. That is a loose coupling between concerns, that should allow you to be flexible in extending and changing the data that a particular function or algorithm could operate over.
In traditional OOP I would think that i’d define a car interface or abstract class then simply inherit from that to create my Truck or Sedan. Alternatively, I might use object composition and create a class called CarEssentials and start bundling a few objects that a car might have. I could even get a little fancier and use a di system to couple them a little more loosely.
I found that within a functional programming language that Algebraic Data types , that I have a natural tendency towards more composition and duck typing happens with very little thought.
Another thing that struck me during this process was , that my functions became somehow much more general ,and less coupled to my types, as well as way more extensible. For instance adding another supported Car type such as a limousine was as simple as adding the type and potentially adding pattern match against my functions to handle it slightly differently if I needed to change one of the functions that operated on a car. So specification of behavior was moved to, the behavior itself versus the Object. A pattern that takes much more effort to do in OOP. I.e. you might have object managers, that know how to perform xy or z . vs functions that operate on types.
Algebraic Data Types rule and I’m excited to continue on this journey.