Comparing Ruby and Haskell, Part II
Let’s continue on with our discussion between Haskell and Ruby. If you missed the first post, check it out here
This is where Haskell and Ruby are incredibly similar. Both have awesome utilities that are built into the spec of the language, meaning that they’re guranteed to be available.
The functions that Haskell provides are incredibly useful, especially for things like dealing with arrays/lists – they are the bread and butter of functional programming languages. For example, the
takeWhile function makes a new list out of a list by taking elements from the existing list while some predicate holds true.
Ruby doesn’t seem to offer the same level of usefulness in global functions, but, all of the objects are chock full of awesome instance methods that make life just much easier for the Ruby hacker.
Haskell’s huge number of built-in methods make it feel very little like C and more like Ruby or Python. C is a minimalistic language – it takes only a few days to learn the syntax and all of the built-ins. However, it makes life quite difficult when writing large programs. With Haskell, this isn’t the case – it is a large specification with a ton of features that are incredibly useful when writing code in the language.
Also, a lot of these functions serve as great learning tools when learning the language. As an example, there is the aforementioned
takeWhile function in Haskell, which you can see in action here:
Basically, it takes a function (which is the
(<5)), checks if it returns true on the elements of the list (taken as second argument), and returns the part of the list until the function is no longer true.
It looks at 1 (gets a true), then 2, then 3 and so on until it hits the 5, upon which it returns the list [1, 2, 3, 4].
Implementing this function is a great exercise in Haskell (don’t worry if you don’t understand a bunch of the syntax):
Without going too far into the details, this function is recursive, and, it basically checks if the function passed returns true. If it does return true , it keeps going (and appends an item to the list.) Otherwise, it ends and returns the list thus far accumulated. All of this is done in three lines of code.
Without any experience with Haskell, the code might look cryptic, but actually, it is really simple.
Many other such functions offer great learning exercises in Haskell.
The Ruby community is quite distributed, and has a great variety of people in it. There seem to be two parts, with convergence in the middle. There are people who work with Ruby and there are people who work with Rails.
Of course, the Rails people all work with Ruby (I’m considering them as seperate, since many Rails people don’t consider themselves Ruby people), but there are very few people that use Ruby that haven’t had a go with Rails. As such, the community for things that aren’t related to Rails is still not incredibly large.
RubyGems are a great place where collaboration happens, and make sharing ruby code incredibly easy.
The community is largely quite accepting. It isn’t all conducted in one place, with small patches of the community going on all over the place.
The Haskell community on the other hand, is really knit together. Their #haskell channel on Freenode reguarly has 900 people (compared to maybe 500 for #ruby). Haskell.org’s Wiki is the central place for all documentation about Haskell.
Cabal is similar to RubyGems, however, there are some issues. Many libraries aren’t as well tested, nor as well documented as Ruby’s. Therefore, it becomes quite difficult to select a good library for a given purpose at times. For example, there’s about a bajillion and six libraries to query databases, out of which 99% are completely useless. However, this happens to nearly all languages in the growth stages, and the community is working hard to try and get this under control.
Lastly, and probably most importantly, the Haskell community is one of the most accepting and patient I’ve ever seen for any kind of technology. Everyone seems to understand that Haskell is a complex language that is difficult to understand in one go and are always willing to help. If you have any sort of problem with Haskell code, the people at #haskell on Freenode are always ready to help. I remember someone explaining to me functors (a big name for something you can iterate on, basically) for over 45 minutes, with me desperately trying to break off ties that I’d mentally formed with OOP. If it weren’t for the connectedness and accepting nature of the Haskell community, the language would still have been restricted to a small group of academics.
Ruby is an incredibly easy language to pick up on, regardless of whether you’re an experienced programmer or a total newbie. It is powerful enough that it works for both.
With Haskell, the situation is a bit more complicated. The language is quite easy to learn if you haven’t doused yourself in OOP yet, because you’re not finding yourself in something totally out of your comfort zone. If you don’t know any programming, Haskell isn’t incredibly difficult to learn, some might say it is easy.
But, if you’re from the OOP crowd (like most of us are), it takes some discipline to try and break out of the mental box that you’ve forced yourself into by writing OOP code. Consider this again: you can’t change the value of a variable. That seems pretty radical, and it is, so the concepts built around it also seem quite radical. But, in the end, it is a very rewarding experience.
When I first started learning Haskell, I just couldn’t understand why in the world anyone would write code like this. It seemed like writing every function was a little bit like solving a puzzle, and, it seemed like a big hit to my productivity.
I still feel like I’m solving puzzles while writing functions in Haskell, but I’ve realized something very important. Even though I’m a bit slower at cranking out code in Haskell, I spend waaaay less time debugging in Haskell then I do in other languages (such as Ruby). This is due to a couple of reasons.
First of all, the compiler is incredible. While keeping a dynamic feel, all types are checked, which allows one to catch a large percentage of errors immediately.
Secondly, referential transparency and modularity allows debugging to proceed much faster than it would with code that has state changes everywhere.
So, even if you feel sluggish at first, you’ll get better quickly.
Haskell is a varied and complex language, as we’ve seen, and most programmers coming from the imperative paradigm find it a bit daunting.
I found the LYAH guide to be excellent (as I mentioned in the previous part). It is written in an entertaining style, and walks you through all of Haskell’s awesome features very well.
Here are some tips when trying to learn Haskell:
* Don’t try to do things that are immediately practical – that will come later
* Project Euler is a great place to practice your Haskell skills
* Don’t try to to learn about monads and functors too early in the game – this will only mess up your understanding
* Experiment around with ghci (a repl-like system for Haskell), it will really help you get a feel for the language
:t flag for ghci is incredibly important – use it well and use it all the time
* Don’t be afraid to ask for help – as mentioned, #haskell is full of people who are eager to introduce newbies to the wonders of Haskell
Hopefully, you learned a bit about Haskell and how it relates to Ruby.
Haskell is an absolutely incredible language that Rubyists should be interested in – it has great many similarties and differences from Ruby, and offers a completely different mindset to programming that needs to be experienced to be understood.
In fact, even if you never write a single line of Haskell code in your life after learning the langauge, it will still make you better programmer. Heck, just learning about recrusion makes you a better programmer.
So, go ahead and try it!