Comparing Haskell and Ruby, Part I

Dhaivat Pandya

Since I’ve started telling computers what to do (also known as programming), I’ve learned several languages. Some of these languages I’ve disliked (C++ with Boost), some I’m “in the middle” with (Perl), and some that I’ve liked a lot (Ruby, Python, Haskell, maybe JS).

At first glance, Ruby and Haskell seem incredibly far apart, having almost no similarities.

Ruby is an imperative language (albeit with some functional elements built into it), but there is no currying (one of the core concepts of Haskell) nor is there any provision for tail call optimization, making recursion an imprudent choice for many cases. Also, it is a very practical language – speed is put behind programmer efficiency. It was popularized by Ruby on Rails which, being a web framework, is probably as practical as it gets.

Haskell, on the other hand, is a purely functional language (if you don’t know what that means, keep reading). Functions are absolutely essential to writing the language and are first class objects (more on this later). The language isn’t immediately practical – there’s quite a bit of reading you have to do before you can, say, build a small HTTP server (that’s actually quite easy in Ruby, with Celluloid.

Looking a little deeper and taking in a bit of both languages (I assume you guys are literate in Ruby; if not, it is much easier than Haskell :)), we start to see very interesting similarities.

The Functional Paradigm

Traditional or imperative programming works a bit like cooking directions. You tell the computer to do this, then do that, and then the other thing. Functional programming works in quite a different way.

Ruby is an imperative language. It may not be immediately obvious (if you haven’t thought about it) but, writing Ruby code reads like a set of directions to accomplish some kind of goal.

When trying to write these directions, there is some changing and holding of “state”. This could meanm, for example, changing the value of a variable. Here’s the shocker – functional programming has no such thing as state. So, no changing variables!

Now, think back to when you first learned programming, and you saw a statement like “x = x + 1″.

My first thought when I saw this was – “Wait, what? Can’t you just cancel the x’s on both the sides, but, then you get an impossible equation…”

With that, all of the math that you’d learned became useless.

But, with Haskell (a purely functional language), it gives you your math back! Since variables can’t change, assignment statements like the above can’t happen!

Imperative languages are quite free with side effects. Side effects are things that happen outside of the “working environment” of a method. For example, it means to change the state of the screen in a method by printing a line.

But, side effects can be really horrible. When calling a method in an imperative language, you have no guarantee that it will do what you intend it to do. The method may return something completely different when called with the same arguments at a later time, because it may be affected by some external state.

In purely functional languages (again, Haskell), side effects almost can’t happen. This also gives us something called referential transparency. Referential transparency means that a function that we call will give the same result for a set of arguments, no matter what happens in the outside world. But, if side effects can’t happen, how are we supposed to print something to the console? Well, this is done by some magic called Monads, which basically try to stuff side effects into a completely pure, state and side effect free environment.

An excellent example of a purely functional language is mathematics. There is no such thing as a side effect in math, because there’s nothing for side effects to effect! It’s all definitions and using those definitions.

How does this compare with Ruby? This is where the languages are vastly different. Haskell is incredibly pure, where everything is squeaky clean and you’re not allowed to make a mess. Whereas with Ruby, if things aren’t done properly, code can become a tangled mess of state changes. Ruby also makes it much easier to perform side effects where needed, whereas with Haskell, it is a royal pain.

The Typesystem

Ruby, as most of us know, has a dynamic typesystem, which means that type detection is performed at runtime. As such, if there is some kind of problem with types of variables not matching, we only find this out a runtime (i.e. it will crash or throw an exception).

This seems quite bad, because we might have programs crashing all the time. However, if you can keep track of your types throughout your program, it speeds up development quite a bit.

If you’ve got any sort of experience with Java (shudder), which has a static typesystem, you know the problems a typesystem like Java can cause.

Haskell has an incredibly strict static typesystem. This, initially, makes most Rubyists cringe and it definitely seems more irritating. But, let me tell you, it is a life saver.

The Haskell typesystem has something called type inference. So, in next to all cases, you don’t actually have to “write down” the types of any of the functions. Because of this, Haskell’s typesystem feels incredibly terse and very quick, while affording the convinience and security of a strict static typesystem.

Ruby and Haskell differ quite a bit at first glance in this regard. One is highly dynamic and fluid, the other is rigid and incredibly strong. But, the end result that comes from both typesystems is an experience that is very agile and swift, letting you largely avoid thinking about types.

However, as a personal preference, I like the Haskell typesystem better. I almost never notice the typesystem. It also gives the extra benefit of awesome typechecking at compile time, to the extent that if it compiles, it probably won’t crash.

An important consideration is the data model. Ruby, like pretty much all other popular languages (except JS), has an OOP model. Haskell uses something called algebraic data types, which take quite some time to explain (especially to people who already have a concept of OOP.) Basically, these data types don’t have a much of a hierarchical structure, and, if used properly, can be incredibly powerful.

Wrapping It Up – For Now

Hopefully, this article gave you a general idea of what functional programming is, and started off the comparision between Haskell and Ruby.

One thing is for sure. If you’re a Rubyist, it won’t hurt to pick up a little Haskell. It may even change the way you write code (it did for me).

In the next article, we’ll cover more similarites and differences of Haskell with Ruby, such as built-in methods (and functions) as well as how the communities of both languages function.

The LYAH guide is an excellent way to get started!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Asher

    How is JS not OOP?

    • Dhaivat Pandya

      JS is not the typical OOP, is what I meant. It is all based on prototypical inheritance, which are basically lookup tables stacked upon each other.

      • 2piix

        Please keep in mind that if JS is “OO” (in virtue of it’s prototype based dispatching system), then so is Haskell. Record syntax gets you 95% of the way there, and lenses fill in the gap and give nice syntax for getting and setting.

  • kelvin

    great article! one thing that changed the way I write code was learning lisp. And yes, I am a rubyist :P I can’t wait to learn some haskell. thanks ;)

    • Dhaivat Pandya

      I think Haskell is a nice mix between the practicality of Common Lisp and the purity of Scheme. I think you’ll enjoy it :)

  • Kamil Ciemniewski

    Nice post, I think a nice comparison between the two would involve “productiveness”. From what I observed – many people have almost a fear for learning Haskell – because of it’s learning curve. And also many think that Ruby gives them an advantage of being very productive.

    While this holds in the beginning of your journey into the Haskell world – productivity gap gets smaller and smaller with every step.

    After some time into digging into nuts and bolts of everyday usage of Haskell, new advantange arises from using it – less need for maintenance because of extreme code correctness. For bussiness it means whole lot of cash saved on not having to chase too many bugs.

    But, really – both technologies are still very exciting even though they’ve been around for a while now.. Both being very innovative give the World a whole buck of new ideas.

    • http://www.nickmabry.com Nick Mabry

      I very much agree. I’m probably in the minority that programmed extensively in Haskell (as part of the University of Kansas’s big language design push) before Ruby. Haskell programming puts me in a very different mindset. The goal is to discover the types and transformations that will reveal the underlying code, as opposed to discovering the types and data that will reveal the underlying structure.

      As one of my professors put it (paraphrased), “If you can get it to compile in Haskell, it probably works.” Once you discover the types and transformations and get the compiler to verify them, the simple operations just work. I feel something similar when programming in Clojure, minus the type checking.

      In heavy-OO languages, like C++ or Ruby, the majority of the work I do doesn’t revolve around getting the compiler to type-check my work, but in distributing responsibilities to collections of data and functions that can take responsibility for them.

      My current favorite theory is that functional programming is preferable for low-level functions and that object-orientation belongs to an abstraction above them, at the system level. But it’s all a lot of fun to learn.

  • paulcc

    Hi – have you seen http:/pragprog.com/magazines/2012-08/thinking-functionally-with-haskell?