Isn't it about runtime macros vs compile time macros aka templates, Haskell has no runtime macros, LISP has them, I'd guess you can manipulate and redefine mostly everything in runtime in LISP, not so in Haskell?
Huh? Which Lisp has runtime macros? I am only aware of 'compile time' macros.
I am most familiar with Scheme (and Racket) and Common Lisp. Could you explain how 'runtime macros' work in any of these systems? Perhaps give some example code?
I was thinking about the difference between templates in C++ or Haskell, which are kind of strictly compile time macro/code generation systems; vs macros in Scheme / Lisp, languages with self-contained compilers/interpreters, due to `eval` and `quote`, which are in basic case evaluated somewhat at runtime. C++ and Haskell do not have `eval`, at least not the early versions, not in the default language specification. So LISP/Scheme as a more dynamic, more runtime languages; C++/Haskell, more static, with compile time template facilities languages.
Haskell (at least as implemented in GHC) has TemplateHaskell, which is somewhat of an inbetween: at a distance it kinda resembles lisp macros if you squint a bit (it's of the "eval and quote" kind, so to say) but it's exclusively compile time. It's also quite unwieldy, and most of the time it ends up being unnecessary because Haskell can do things through other means. Laziness for control structures, Typeclasses with all the extensions for code generation... nowadays I only really see Template haskell used for two things: generating top level bindings that don't really belong in a type class (e.g.: singletons, lens, polysemy) or embedding of another language (yesod's hamlet, or some sql libraries). Haskell is not really built to support macros from the start, they're seen as more of a necessary evil, IMO. If you've used rust before, it's kinda like rust macros except worse :)
I am not sure if exclusively compile time `eval` is possible, by `eval` I mean `eval` that should handle I/O just fine. Such `eval` would make for compilation that possibly never ends.
I think `eval` along with `lambda` is slightly mind bending distinguishing feature of LISP/Scheme, but for sure, dedicated, optimized eval-less LISP/Scheme are possible and exist, if we consider s-expressions the distinguishing feature. Prolog is another language with elegant circular-meta-interpreters.
Python has both eval and lambda these days, and is not normally considered mind bending nor a Lisp. Even C++ and Java have lambdas these days.
(To be fair, Python's 'eval' operates on strings, Lisp likes its eval to operate on something much more (but not quite) like abstract syntax trees. But it would be relatively straightforward to make a version of Python that uses s-expressions and has an eval that works on them; without changing anything else about the language.)
Apart from matters of parsing, being able to build elegant circular-meta-interpreters isn't too hard nor special, if your language is reasonably simple but still has enough functional programming features.
As I said, you can make a version of Python that uses s-expressions without changing anything else about the language. You can even give that same treatment to C! Python is also perfectly capable of manipulating s-expressions at runtime. (It's much more of a hassle in C. But that's because almost everything is more of a hassle in C.)
Homoiconicity is fun, but it's not a very deep property of your favourite language.
Well, many LISP systems do compilation (and macroevaluation) at runtime as well, so there is really little distinction. That is, `compile' and `eval' are common functions in many LISP implementations, and they can be called like any other function.