Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

Some Lisp advocates may tell you that Lisp even does not have hygienic macros. Lisp dialects like Scheme have. Lisp usually has procedural macros, which transform source code (in the form of nested lists), not ASTs (like Nim).

That Nim has 'powerful hygienic macros' is fine, many languages have powerful macros.



sort by: page size:

What problems do you run into? I'm familiar with lisp's macro system but didn't get to look into hygienic macros in other language, and was wondering if they are equivalent.

Common Lisp does have macros, but not hygienic macros.

>much easier to write macros (code that writes code) and facilitates compile-time computing

Isn't this a non-issue in scheme as it has hygienic macros?

Note: my only exposition to lisp is via elisp, so I might not know what I'm talking about.


In Lisp, my understanding is that while you can manipulate the AST directly, you will likely introduce a bug unless you use the special functions for handling hygienic macros? And each flavor of Lisp has its own way of doing hygienic macros.

Still, isn't it AST-based in the sense that the input of a Lisp macro is effectively a parsed syntax tree, just as in Nim?

Correct me if I'm wrong, but Lisp-2 vs. Lisp-1 has nothing to do with hygiene, it just splits Scheme's single problem (lexically binding values in macros) into two problems (lexically binding values in macros, and lexically binding functions in macros).

The real problem, which Naggum includes, is the lack of GENSYM (if scheme indeed lacks it), and lack of first class symbols, as he mentioned.


The debate over hygienic-macros is not as straight-forward: https://groups.google.com/d/topic/comp.lang.lisp/dcX15VC5BdM...

Some* argue that hygienic-macros are an unnecessary burden because sometimes you need to capture variable names and this is easy to do with Common Lisp. The situation with Scheme is different because it stores variable and function definitions in the same way (Lisp-1 vs. Lisp-2).

* http://p-cos.net/lisp/guide.html


This is true in Elixir as well, which has hygienic macros very much like a Lisp. There's a balance, of course, but it really is quite nice to be able to just rewrite the AST as you need. And one must always remember the adage data > functions > macros.

I am admittedly still a Lisp (et. al.) rookie, but isn't the entire point of Scheme that it introduces hygienic macros? Or are you referring to some other (perhaps sarcastic) notion of macro hygiene?

R5RS hygienic macros qualify as LISP goodness, but a lot of Scheme implementations also implement defmacro (like CL) and/or syntax-case.

Use of macros makes the code reflect the programmer's thinking about the problem domain. Whether this is readable or not depends on the programmer.


Unhygienic macros aren't a C-ism: hygiene was an innovation (I think originally in Scheme). Ordinary Common Lisp macros are unhygienic.

Hygienic macros and a strict phase separation are not distinctive to scheme, many languages have this now, most importantly Rust. And just like Rust macros scheme macros are not really an organic part of the language but some extra edifice bolted on top. Scheme definitely deserves credit for pioneering work here, but the only aspect that's of enduring distinctiveness that I'm aware of is Racket's #lang, which basically gives you a less messy and more powerful version of what you could do in Common Lisp with macros and read-tables.

My impression is that hygiene itself (which the scheme community tended to obsess over) is of minor practical benefit, but the fact that you get good error locations (because not using plain lists and symbols makes it easy to carry sufficient contextual information around[^1]) is a major upside.

Out of curiosity, are there additional important practical benefits you see, macro-wise, over Common Lisp (that would make up for the gimped repl)? I.e. in addition to better error messages?

[^1] I seem to remember being told Allegro Common Lisp does a good job here, but I assume identity still imposes some major limitations.


Yes, but Nim's macro system, while very powerful, is, at present, the most clumsy and awkward thing I've seen. it's imperative, like Lisp macros. However, unlike Lisp macros, there are no templates, and the datastructure that Nim's macros manipulate is much closer to the actual AST, and thus far more complex. Because of this, Nim macros must clumsily plug together an AST, and do so in a manner that's so noisy that you have to squint to see what it's actually doing by the time you're done. Meanwhile, Lisp macros are not necessarily shorter, but it's far easier to see what's going on.

Hygienic macros are a bigger deal in Scheme, where everything is conflated into single namespace (you know, the land of LST). His rant about macros and namespaces is a good hint he didn't practice Lisp that much.

First, can you talk a little about how Nim's macro system is more-powerful than Lisp's? That seems like a fairly broad claim, and unless it allows you to influence the compiler at compile time (and maybe even then), I am curious how that works out.

Second, one of the biggest issues with lisp is that macros end up sort of slow, especially when you're using them + lists to replicate ADTs with pattern matching (versus, say, ML, which can do very fast dispatch based on types). Doesn't Nim fall into that same trap?


This problem exists, but it is equivalent to problems Common Lisp programmer has to face if he writes macros, and solutions are similar. In CL it is solved with gensyms, and Scheme hygienic macros automatised that. Similar approaches are possible - and practiced - in Newlisp.

Common Lisp do have optional typing though, and hygienic macros is a controversial subject. Dialect scoping is cool though

I know both Lisp and Scheme pretty well. Scheme's macros are hygienic, Lisp's macros however are much easier to handle. The hygiene problem can be solved by using (gensym) for local identifiers. Example:

http://stackoverflow.com/questions/267862/what-makes-lisp-ma...


You're really very wrong on Nim's macros. It follows Lisp's defmacro tradition instead of Scheme syntax-rules/syntax-case, but that doesn't make it any less powerful (many would argue it's demonstrably more powerful). You are also dead wrong on syntax-rules/syntax-case capabilities, or maybe on what the syntax/AST is, if you think that there's anything they can do that Nim can't. Both systems deal with AST which means they both are unable to introduce new ways of parsing the code, only transform already parsed one. In (some) Scheme and Common Lisp you get access to readtable, which is the parser, but that's really a different thing. And even in Lisps it's not that popular: Clojure and Emacs Lisp disallow this for example.

Personally I favour pattern-based macros, like the ones implemented in Dylan, Elixir or Sweet.js (to show some non-sexp-based languages with such macros); but there is nothing "wrong" with procedural macros and they are not, in any way, less robust.

You don't have to be excited by Nim, but you should try to avoid spreading lies just because you aren't. Maybe a "lie" is too strong a word, but this statement: "Nim's macro system seems to be far less robust than that" is really very wrong and I wanted to stress this fact.

next

Legal | privacy