Hari's CornerHumour, comics, tech, law, software, reviews, essays, articles and HOWTOs intermingled with random philosophy now and then
Why learning Functional Programming and Haskell in particular can be hard
Tutorials and HOWTOs by
Posted on Mon, Oct 31, 2011 at 19:52 IST (last updated: Fri, Dec 30, 2011 @ 15:30 IST)
factorial (0) = 1 factorial (n) = n * factorial (n-1)What it means is that you define a factorial of a number N as the number N multipled by the factorial of N-1. So the function calls itself till it calls factorial (0). This is called a "base case" (where recursion is terminated). This is fairly easy to understand. However, it is far from intuitive from the point of view of working out a solution for a problem that one might solve using an iterative approach. A real world problem may illustrate this better: counting pebbles. The instinctive way to counting a number of pebbles that are laid out in a row is simply to point a finger at each pebble, one at a time, and mentally increment a counter for every pebble you point at. This is an iterative approach. Another less obvious (but still easy) method is simply to pick up a pebble and keep it in your palm and repeat the function until you run out of pebbles. The number of pebbles in your palm at the end of the process is the answer. You've just "folded" the problem using an accumulator (your palm) instead of using your finger (counters). Of course, there will always be a debate as to which is more efficient but that is besides the issue but I think it's a good way to mentally "map" recursion and iteration as any. Functional programming favours the second approach and FP languages support recursion by optimization techniques, even implicit recursion through folding - a concept that keeps recurring in the FP paradigm. Recursion is only the tip of the iceberg though. But it is certainly an early barrier that needs crossing. Too much theory can be off-putting One thing I found when searching for tutorials/articles on Functional Programming is theory. You'll run into a lot of theory and they can easily confuse you and lead to a conclusion that "functional programming is for academicians". While it's inevitable that you need some grounding in mathematics for functional programming, it's not strictly a requirement. But even then, the terminology can be heavy, especially with relation to the more advanced concepts like Functors, Monoids, Monads etc. I confess that I still don't know them and trying to even familiarize myself with them is frustrating. I would suggest that letting go of these topics initially and focussing on the basics as more important. Tutorials that make it seem simpler Actually for Haskell, the excellent guide "Learn You A Haskell for Great Good" makes Haskell seem ridiculously easy at first look. But actually the learning difficulty begins when some of the more advanced concepts are introduced. Pitfall one for most people I expect will be "higher order functions." It doesn't become 'slightly harder' after that. It becomes ten times harder unless you are already conditioned to functional programming intuitively. Actually I would recommend reading a few chapters early on and try to really grasp the basics first. Going too fast, like with imperative programming languages, will lead to confusion. Everything "looks" intuitive in functional programming when presented as a solution (ignoring the more advanced concepts and syntactical complexities involved, for a moment). Arriving to that solution is precisely where you find the roadblocks. My recommendation would be probably to swallow the concepts in small bits and write working code on your own for simple programs using those concepts. It might be slow going, but then again, learning is never a piece of cake. Forget the Zealotry or just ignore it This might seem controversial, but a lot of articles I read on the internet sound a lot like zealotry to me, extolling the virtues of Functional Programming and making it appear that imperative programming are for the mentally inferior ape-types. Sure, that is putting it a bit high, but it can be a bit depressing to read such articles. Whether FP paradigm is truly superior or not is besides the issue. Point is, to a newbie, it can seem daunting and downright depressing to see your second nature (read: imperative programming methodology) trashed like that. Frequently you come across "code samples" solving the same problem: one with the imperative approach with exaggerated clumsiness and the other (almost unreadble, but elegant looking) functional solution ("isn't that clever!" kind of solutions) Ignore that (except for the code bit which can be educational once you're more comfortable with FP). Such talk/writing adds nothing of value to a newbie and to my mind it creates too many expectations about what FP can offer. While terms like "expressive", "rich", "elegant" and "graceful" are thrown around frequently in reference to FP, to a newbie it is just marketing talk in my opinion. Maybe it can deliver, maybe it cannot. But as a newbie, such articles are a distraction from learning and can even lead to demotivation (why don't I just *get* it?) And finally... The above are just some of the few pitfalls that a programmer new to FP paradigm (with a focus on Haskell) is likely to fall into. I might add, there are a few other points to add to the above, but they are relatively minor and can be overcome with familiarity and practice.
- Type system: This is specific to Haskell, but nonetheless, the strong, static type system can be an irritation and annoyance to those used to dynamically typed languages. However, with practice, it gets easier to understand and one actually begins to appreciate its strengths.
- Syntax and syntactic sugar: I never heard of the latter term until I came across Haskell and I confess that these elements can be a bit confusing at first. Every new programming language (including imperative languages) has this issue, so it's not unqiue to FP paradigm (though it can be a slightly harder hurdle in FP).
- Associativity: This is another common term used in FP paradigm and learning the associativity of functions can be a little confusing as can concepts like compositing, currying etc. Simply learning to "read how this code works" can be challenging at first and takes time to begin to understand.
- Laziness and lazy evaluation: This is specific to Haskell and while the concept itself sounds very intuitive, it can be a bit confusing to understand "how" it works in practice especially if you're still thinking like an imperative programmer. I would suggest forgetting about understanding it and just take it for granted until you run into a situation where it actually matters whether a function works lazily or not.
In this series
- Musings on Functional Programming and Haskell
- Tic Tac Toe (a.k.a Noughts and Crosses) in Haskell
- Five tips about Functional Programming for a Haskell newbie from a Haskell newbie
- My Haskell article was linked at reddit
- Why learning Functional Programming and Haskell in particular can be hard
- Something about Haskell I wanted to share
- So on to learning Haskell