Haskell is just some steps away from Java

Start with Java, then:

  1. Forbid using null;
  2. Use only immutable objects, add “final” modifier to everything;
  3. Swap methods by static functions with the the original “this” as the first argument, e.g. “foo.bar()” turns into “bar(foo)”;
  4. Add a lot of features to the type system;
  5. Remove type annotations, i.e. “Foo bar(Foo self)” turns into “bar(self)”;
  6. Remove useless parens, i.e. “bar(foo)” turns into “bar foo”;
  7. Add call-by-need evaluation;
  8. Done, you have Haskell.

It’s not that hard, is it?

One, using null references is a recognized bad practice, see “Null References: The Billion Dollar Mistake.” Java 8 already provides the Optional type to stop using nulls.

Two, immutable objects are a win strategy, see posts by Hirondelle Systems, IBM, Yegor, and others.

Three, as you only have immutable objects, there is no reason to use methods instead of static functions, considering you maintain polymorphism (not quite the case for Java, but for the sake of this rant, consider as if it has this feature).

Four, improve the type system. The type system used by Java language misses a lot of features. If you don’t feel it, just consider this as an added bonus. When you start using the type system features in your favor, you end up with much better code.

Five, imagine the Java compiler could infer the type of the arguments, so you don’t need to type them everywhere. You still have the same static typing language, you just don’t need to write the types. Shorter code means less liability to haunt you.

Six, why all those parens? Just drop them. Less code to write, hurray!

Seven, call-by-need just makes a lot of things easier (also makes a lot of things harder), but I really think it is a winner when you talk about productivity. When coding, I feel it a lot easier to express things in terms of values instead of steps (mathematicians have been doing this since long before computers). Expressing things in terms of values in a universe without call-by-need will result in a lot of useless computations, so call-by-need is a must.

Eight, done! This is Haskell. No functors, monads, arrows, categories or lists needed.

Why this post? Well, I don’t know. It just occurred to me that if you really go into following good coding practices in Java (e.g. avoid null, use immutable objects), you will eventually feel familiar with functional code. Add some more things to the mix, and you end up with Haskell. I think people feel a bit scared at first contact with Haskell (and family) because of the academic and mathematical atmosphere it has, but in the end it is just a lot of good practices that you are kind of required to comply with.

Advertisements

4 thoughts on “Haskell is just some steps away from Java

  1. I think you're omitting the most important difference: referential transparency. Without it you can't implement call-by-need in a sane way. If forcing a value can result in side-effects then you need to describe each computation as a series of steps in order to control the order of the effects.

    At that point you've reintroduced the concept of a monad, which is simply a sequence of actions where later actions can depend on the results of previous actions. All imperative languages are monadic in structure, even if they don't use the term explicitly. By enforcing referential transparency, Haskell gives you a choice: pure code can be call-by-need without any concerns about side-effects, and if you want to carry out a sequence of steps you can express them as values within a monadic type.

    Like

  2. Referential transparency is somewhat at step 2 (immutable only). It's an exageration of the “immutable objects only”, so you would need to stop using standard classes from the JDK and start using some libraries that support it.

    In fact, monadic code is *pure and referential transparent* in Haskell. They are just a representation of an action, so nothing really happens until RTS “executes” the actions.

    So, “monads” are just one nice way to represent actions, but they have no magic in it. They are just the same as other values in Haskell.

    Like

  3. My point was that if you want to use call-by-need then you need to make the distinction between I/O actions and pure code explicit, rather than treating everything as an I/O action the way imperative languages do. Whatever terms you prefer to use, I/O actions do form a monad; you have a way to turn a pure value into an I/O action (“return”) and a way to take the result from one I/O action and use it to produce the next I/O action in the sequence (“bind”). Imperative languages don't tend to talk about monads not because they don't have them, but because in an imperative language there is no such thing as an expression which _isn't_ a monadic action. In a language with call-by-need there has to be a distinction between I/O actions with externally-visible side effects and pure code. The fact that not all code in a call-by-need language is monadic forces the programmer to become aware of monads in a way that imperative languages do not.

    (Incidently, this comment system has a tendency to eat my first drafts. When I click the “Preview” button the page reloads, without the comment I just entered. The back button doesn't help, since the comment form is dynamically generated and not part of the original page. I think this reload is related to the login system; it only happens the first time. In any case, it's very annoying.)

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s