Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Haskell's syntax isn't actually that complicated. There are some common functions with operator names that can be hard to read if you're not used to them, but those are library defined. The syntax itself is actually fairly simple.

And incidentally, this would probably be something like (EDIT: made example more realistic):

  filter personIsValid (map initPerson names)
in Haskell. Which looks much cleaner than the lisp to me.


Except in these two brief examples, Haskell employs syntactic sugar with hidden semantics that nobody but an acolyte would understand (periods and two kinds of brackets mean what?). At least the Lisp scoping here is explicit and employs minimal abstruse sugar.

I'll admit Lisp's myriad nesting of brackets is not ideal either. But surely there are more elegant and intuitive notations for functional scoping than is seen here.


I'm not sure what you're talking about? My example contains no periods and only one kind of brackets? Did you reply to the wrong post?

Admittedly, it might be written with $ in practice, but that's a fairly simple idiom, and I tend to avoid it.


Lisp provides its own solution to the nesting of parentheses: if you're writing an expression which is too deep, you can invent an ideal syntax which more direclty expresses what you want to say. Then teach Lisp to understand that syntax. Then there is a myriad of parentheses in the macros which implement the syntax; elsewhere, there are fewer parentheses.

Very simple example: once upon a time, in the early 1960's, Lisp only had the COND operator. There was no IF. Programmers often had to make two-way decisions using COND, writing things like (COND (condition then-expr) (T else-expr)). Too many parentheses. So they came up with the IF macro allowing (IF condition then-expr else-expr). This simply expanded to the COND. Six parentheses are reduced to two.

Like most other programmers, Lisp programmers care about not writing mountains of distracting, irrelevant code that is hard to understand. That's why the backquote syntax was invented for instance. Before the backquote syntax, macros were difficult to write.

Say you wanted to transform the syntax (foo bar) into (let ((bar (whatever))) (do-something bar)).

You had to write a macro function which took the object (foo bar) as a single argument, analyzed it, and then constructed the output. Suppose we already have the BAR part of the (foo bar) from in a variable called SYM. Then we have to do something like:

   (list 'let (list (list sym '(whatever))) (list 'do-something bar))
   ;; I'm not going to bother to get this right
With the invention of the backquote, this could be rewritten like this:

   `(let ((,sym (whatever))) (do-something ,sym))
A nice template which looks like the output that we want, and indicates the places where we want to stick the variable BAR symbol, held in SYM.

Obviously, backquote templates have parentheses. But the notation itself isn't parentheses; it consists of the backtick syntax, and the commma operator for interpolating values. Also a ,@ operator for splicing lists. In some Lisp dialects, the backtick is transformed into a nested list object. For instance `(a b ,c) might turn into (quasiquote a b (unquote c)) "under the hood".

Lispers also invented destructuring: being able to write the macro with a kind of pattern match for the syntax, so that the elements of the to-be-transformed-form are pulled apart into separate variables.

Lisp is not a finished language. New ideas continue, and new surface syntax like the backquote is not off the table. Usually, Lisp programmers would, I think, prefer that such new syntax integrate into Lisp by not "disturbing" surrounding syntax by involving it in ambiguity. Something tidy and simple that has a big payoff is best.

Lisp programmers are not tone-deaf to notational advantages, and do not regard macros as the one and only way to reduce verbosity.

I'm conducting my own one-man research program into improving Lisp and have come up with some great new ideas.

I have a Lisp dialect which is quite ergonomic, leading to terse programs for everyday "data munging" tasks (and continuing to get better).


That's because your code assumes those convenience functions exist while the parent's code writes out the anonymous functions.

The direct translation of yours' to Clojure would be:

    (filter valid-person? (map init-person names))
Meanwhile, the direct Haskell translation of the parent comment is:

    filter (\p -> isValid p) (map (\n -> Person n) names)


No one would ever write the latter, because (\p -> isValid p) is equivalent to isValid.

However you're right that the function names would probably be a little longer in practice, and I've edited my example to reflect that. (But they're not convenience functions, they just have longer names due to Haskell's more limited namespacing)


Not a Haskell expert, but maybe monomorphism restriction can require you to perform an eta abstraction. Just saying.


Huh? No, anyone who writes it in Haskell would not use those lambda abstractions. You would just use "filter isValid (map Person names)".


I'm assuming Person is a record constructor, is isValid here a field in that record or another function?


Haskell doesn't distinguish the two. If you define Person with named fields including isValid, you automatically get a function named isValid that returns that field, or you can write your own isValid function that examines the whole Person.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: