Saturday, March 8, 2008

Lisper's first look at Haskell

I started learning Haskell a week ago and after few days I already wrote a lengthy essay about Haskell, and most of it wasn't singing praises to it. Quite the contrary, it was how it sucks. The reasons vary but it probably has something with lispers' being spoiled brats. They're damn hard to impress. You show them the cool feature that your favourite language has and they either already have it, have something better or they've already seen it and decided it's not such a good idea as you might think. So this essay is from lisper point of view. I doubt that users of other languages will find much use of it.

But first things first. Let me tell you why I decided to learn Haskell.
1st Haskell is purely functional, variables could get assigned once only, so I wanted to know how the hell they deal with keeping state.
2nd Few lispers like Slava and Frank knew Haskell.
3rd Haskells' code is very compact.

So I grabbed Winhugs and went Huskying. I quickly went through YAHT but I was really disappointed. That made me into writing that lengthy Haskell sucks rant, but after little thinking I understood that I was learning Haskell the lispy style, read Gung-Ho. Damn,I was practically trying to write lisp in Haskell and whenever Haskell complained I was furious. So I decided to give it another shot, this time with Haskell The Craft of functional programming. Halfway through the book I decided to clean my mind of my current thoughts about Haskell by writing this article.
So it presents current state of my mind. Keep in mind that I'm a multipass doer, it needs several iterations before I make something good. So I'll start with little philosophical view.

Design of Haskell:

There is a nice article called What is a Ryu? that explains the definition between a classical japanese martial art, koryu and modern ones like judo. I found it very enlighting in comparing computer languages. To save your time from reading it I extracted few paragraphs. So what's difference between ryu, classical martial art and do, modern ones.
The word ryu roughly translates to style or school but the real meaning is "to flow, flowing... system or school," and here's how Wayne explains how the ryu is created.:
The founder of the style experienced what amounted to a divine revelation. These experts had already developed a vast repertoire of technical knowledge through a study of martial methods and through actual experience in battle and/or in training. But having exhausted and reached the limits of their technical expertise, they consciously underwent shugyo, or a rigorous training that tested their mind, body and spirit.




Often enacted in the confines of sacred ground such as a Shinto shrine or Buddhist temple, or in a hidden religious refuge in the wilderness or mountaintop, shugyo was meant to crack through the surface layer of the physical world to lay bare the secrets of the spiritual universe. Like the intensity of Zen training, after exhausting the everyday avenues of awareness, the trainee undergoing martial arts shugyo attains a new and enlightening insight.

After this period of intense training, prayer, and some kind of fasting and/or abstention, a vision would appear to the founder, that would give him the key to true mastery of his art. Often just a simple phrase or very rudimentary technique(s), the revelation would be the key that unlocked all the subsequent methods that the founder would develop. As such, the revelation was tenshin shoden, or knowledge bestowed from the Heavens, or muso; knowledge gained from a heavenly dream.

The knowledge, therefore, was heavenly pure when it was first passed from the gods to the first generation. If it is to remain a divinely inspired system, then it must always flow back to this person, the founder. Hence, the term -ryu, or nagare; it is a flow back to the wellsprings of the style, which was divine inspiration.

Now let's compare ryu with do, meaning the way. the modern craft.

Judo, as a do form (a "modern" type of martial art stressing mind, body and spiritual development over self-defense or combative methods), is just judo, period. You may have a Kodokan style of judo, a Japanese college style, an Olympic style, but because it is so all-encompassing, there are no ryu in judo. Judo is so malleable in techniques, and is so reasonable in its scientific application of contest-oriented grappling methods that it continues to grow and innovate in technical complexity. It is in fact difficult to truly innovate and create something completely "new" under the sun. Most of us martial artists in this day and age simply aren't capable of such stunning originality.

In case you skipped Muromoto description , ryu is something created with divine inspiration, deity called Alonso Church visited John McCarthy and he combined that vision with s-expressions and made something original, something beautiful.

The first lisp. Common lisp, scheme and emacs lisp are just ryuha (factions ) within a lisp ryu. They're part of the lisp flow but they ain't so pure like the founders original idea. That's why Paul Graham tries to get back to the roots of the original lisp with his Arc. Will he succeed that's another question.
From the other side we have do, 'modern' martial arts they "were developed by committees of human beings, whose attempts are in synch with the modernist trend that things can always be improved with time and human ingenuity.". Most of the modern languages are like do martial arts. Those are languages that weren't blessed with heavenly inspiration. It isn't that their authors wasn't smart or they weren't great programmers, quite the contrary, it's just that muse of inspiration didn't visit their door when they were designing their language. So they did what they did with what they had.
Haskell is one of those 'unblessed ', modern do languages sharing company with c++, java, c#, OCaml, F# etc. If you compare Haskell with some ryu language like Prolog, also one I recently started learning, the difference is obvious. When I tried Prolog I said 'Wow', all the language could be made just from rules ( facts are just degenerated form of rules). On the other side we have Haskell with their bulky kernel language and complex rules of composition. Haskell designers took features from older languages Lisp and Prolog and mixed them together with their own ideas. That's nothing wrong with it, humans build on existing foundations. The problem is that they failed to unify those techniques, so instead of making a monolith tool they ended with "a mess of illogical patchwork". It's not that result is unusable, quite the contrary, but it's not a masterpiece either.


After this philosophical introduction let's get little practical. How does programmming Haskell feels.(This list will probably get changed as I'm learning more of the language)

The good :
1. It teaches you a lot about functional programming. Lisp encourages functional programming , but Haskell enforces it. So all your nasty habits you picked up coming from imperative and object oriented languages will have to go away. There is no looping and variables could be assigned only once. Most of the Haskell constructs for functional programming are already in lisp, but lisp allows you to write imperative and OO code if you want. That won' t do in Haskell. Remember about the composing functions , and returning functions as values. Well I didn't used them much in my lisping. Haskell taught me about their value.
2. You got compact code for free. As soon as your c program is working its probably fast. The same goes with Haskell, as soon as your code is working it's short. With lisp you usually have to work to make your code with c-s' speed or haskells' size.
3. You'll learn a lot of functional constructs, that could find a good use in your lisp arsenal, point free programming, curry, uncurry, flip etc.
4. You'll understand the value of laziness and generators. There's a cool library called heresy made by Matthew Lamari. And you might befriend with your old but long forgotten acquaintance series
5. Built in pattern matching - it's very convenient about programming sometimes. Unfortunately for someone who learned Prolog before Haskell, Haskells' pattern matching will look very limited.
First it doesn't allows me to repeat a variable in a pattern , second compared with Prolog, it's one sided. Big issue for someone used to full power of unification.
6. Algebraic data types are neat.

The bad:
1. Static typing sucks. It reminds me of the dark ages of programming in the c family of languages. Inference engine saves me from writing the boring type declarations but it's far from perfect. I have nothing against static typing if it's optional. One of the coolest features of lisp that I found when I started learning it coming from c++ was thatI could put anything into lisp containers. And I don't want going back.

2. No rapid development. Don't get me wrong, developing in Haskell is faster than in c++ or c# but compared with ultimate RAD vehicles like lisp or prolog, haskell looks like a family caravan against full blood racers. Haskell doesn't allows me to experiment. It doesn't allows me to create modulus with some functions undefined or defined wrong. Bundle this together with loading file to redefine a module, the cruppiest feature they took from Prolog and you'll start to value your lisp listeners.

3. Hogs a lot of brain resources. It's syntax is complex, and together with static typing it forces me to spend more resources on dealing with language than with dealing with the problem.

4. Inflexible- Remember the Alan Kay quote - Lisp isn't a language it's a building material. Not so with Haskell. You can not wrap the Haskell around the problem as you can do with Lisp. Haskell forces you to work the other way around.

5. Spartan development enviroment. Compared with lisp offerings WinHugs looks poor man's IDE. There are so much things that are missing that I don't know where to start. Beside I had to write Haskell code in notepad, best editor available under windows, after Crimson failing to start after I switched to Haskell mode. And don't even dare to mention Emacs, a lot of people don't like it.It's 2008 and creating a simple Haskell editor is not an rocket science. I need an integrated editor with syntax coloring and intellisense kind of reminding me how many and what type of arguments function takes. That's it. Another option is Visual Haskell, used as editor togather with winhugs, for interactivity. Also there is no debugger, so forgeth about stepping, functional style of Haskell, helps here but it's just a hassle debugging by hand.
Update :
Greg Buchholz adviced about GHCi debugger so I will check on it and advice later.Personally I would be happier with something for hugs.

6. Lacks reflexive abilities. Oh silly me of course it lack them. In Haskell everything is carved in stone. Programming in Haskell is like proving a mathematical theorem. There is no screwing around. It's like life in a monastery, full of fasting, preying and compassion under the all seeing eye of the abbot, punishing you for every mistake. So if this kind of life is for you, you'll end up in heaven, but if you want playing around and can't (don't) want life without women, parties, drinking and good food than Haskell is definately wrong choice.

7 and 8 are probably more personal than the others. But this whole post is personal. :)

7. Case sensitive - why does types has to start with uppercase and functions with lowercase. To make it easier for the implementation writers? Or to enhance readibilty. The latter has other way to be achieved. Any syntax coloring editor is smart enough to gave you visual clues what the hell some name means.

8. Indentation matters.






17 comments:

  1. You might like to look at the GHCi debugger, Visual Haskell for an IDE, HS-plugins for dynamically loaded code with eval, Data.Dynamic for containers with anything, and Template Haskell for compile time metaprogramming.

    ReplyDelete
  2. Interesting choice of implementation, GHC is more actively developed and targeted by many Haskell programmers out there. It comes with an interactive shell ghci, which works very well if you run it under ansi-term from within Emacs, along side a buffer containing your Haskell code.

    ReplyDelete
  3. I already know about Visual Haskell, but it's not interactive and I had to install Visual Studio, which grows into a bigger bloatware with each release. But it's an option to use it togather with Winhugs.
    Thanks for the other comments,I will check on them, especially about debugger, though I hope there is a one for hugs. But I'm flexible.

    ReplyDelete
  4. I found winhugs easier to start with under windows. I currently don't have an access to *nux machine and emacs is sort of impurity under windows. Beside I never liked Emacs. I use slime, that has an emacs part, for sbcl lisping, and it's a nice enviroment but it just doesn't have a place in my hart.
    Later I might choose to look at GHC,but for now Winhugs will do.

    ReplyDelete
  5. You said:

    "it doesn't allows me to create modulus with some functions undefined or defined wrong."

    That's incorrect. To leave a function undefined, you'd write:

    foo = undefined

    ReplyDelete
  6. I found the digression about "ryu" and "do" very nice and fitting. I'll include piet in the ryu category :)

    Apart from that, just one note. The Okasaki's pointer to his thesis is kind of off. Practically all of Okasaki's code is - AFAIU/K - in an extended Standard ML which introduces lazyness. No Haskell.

    ReplyDelete
  7. There is a little Eclipse plugin for Haskell, which provides at least some syntax highlighting and it shows errors as soon as you hit ctrl-s for saving the file. Works well with GHC.

    ReplyDelete
  8. Don
    I don't want to explicitly tell to Haskell that function is undefined or that definition is wrong or incomplete. I want to let me continue with my business unbothered.

    Marco
    I'll add APL,J,K & Q in this group. Piet looks cool but I'm not much in a painting.
    You're right about Okasaki will remove the references.

    Frank
    Thanks for the info but I,m already done with Haskell and don't want to do anything with statically typed functional langauges.

    Leslie
    Thanks for the supportive words

    ReplyDelete
  9. I recently tried writing a program in Haskell (because Lisp's runtime was too big), and discovered that Haskell has very little support for structs. Structs can be created with an algebraic data type, but if there's a function to be applied to only one field of a struct (yielding a new struct), all the other fields of the struct have to be explicitly copied.

    Just imagine having to write

    foobar Foo { field1 = x, field2 = y ... } = Foo { field1 = f x, field2 = y, field3 = z, ..., ..., ...}

    It's not so bad if you only have two fields, and you only use the struct in a couple of functions, but any more complexity than that and there's an explosion of repetitive typing.

    Simulating data-field inheritance is another task that can force you to type the same code (in subtle variations) over and over again.

    Template Haskell is a nightmare. It has something resembling quasiquoting, but it's not really. Things that look like they should compile don't, for various reasons. There's about 12 basic types that a fragment of code might have.

    ReplyDelete
  10. Wanna learn functional programming by using a purely functional language? Would you like an Haskell-like language without monads kludge? Go Clean:

    http://en.wikipedia.org/wiki/Clean_(programming_language)

    Wanna convert your Haskell reading skills to Clean? Here we go:

    http://www.st.cs.ru.nl/papers/2007/achp2007-CleanHaskellQuickGuide.pdf

    Haskell has the buzz, Clean delivers.

    The IDE is up to date only on Windows. I don't know if that fits your bill.

    Cheers

    Elena from c.l.l.

    ReplyDelete
  11. Clean hasn't had a release since 2006-12-18

    ReplyDelete
  12. >Structs can be created with an algebraic data type, but if there's a function to be applied to only one field of a struct (yielding a new struct), all the other fields of the struct have to be explicitly copied.

    >Just imagine having to write

    >foobar Foo { field1 = x, field2 = y ... } = Foo { field1 = f x, field2 = y, field3 = z, ..., ..., ...}

    No, that is not true. You can write it like this:

    foobar :: Foo -> Foo
    foobar foo = foo { field1 = f (field1 foo)}

    ReplyDelete
  13. Imagine you're reading a blog post, and it starts "I've been using Lisp for a week now, here's why it sucks...". And worse yet, the blog post goes on to say stupid things like "Lisp's overuse of parens suck" or "Lisp macros are just like C's preprocessor macros, and suck just as bad". What would your response to this imaginary blog post be?

    Let me guess: it wouldn't be polite.

    ReplyDelete
  14. Sounds like you prefer dynamically typed language. You should give Clojure (http://clojure.org/) a go, it's a functional Lisp,

    You should also check out Pure (http://code.google.com/p/pure-lang/), it's sort of a Lisp with Haskell syntax, and term rewriting means that its pattern matching is more powerful than Haskell's.

    Haskell is great if you really care about static types, purity, laziness. Otherwise the steep (un)learning curve might not be worth your time.

    ReplyDelete
  15. @joop
    Clojure is fine, I'm just to tired of all Java related at the moment.

    @Brian
    My response would be to look for a different language that suits their style and needs better. S-expressions aren't for everybody and there is no one uber language. If you coding lisp for 2 weeks and hate it why bother?

    @therac25
    If I find time I will post a reply why dynamically typed suit me better at the beginning though I want type system after my code base stabilizes.

    I'm closing comments for this blog there is just to much spam

    ReplyDelete

Note: Only a member of this blog may post a comment.