2

Apparently it is harder to add macros to Haskell than Scheme.

I'm very confused on what exactly macros are in functional programming, but from what I understand in C it is code which alters the "code" at preprocessing time, rather than the program itself.

Is it something to do with the fact that Haskell is pure, so it much harder to alter functional code?

Has it something to do with lazy evaluation?

Greg Peckory
  • 7,700
  • 21
  • 67
  • 114
  • 3
    *Is it something to do with the fact that Haskell is pure, so it much harder to alter functional code?* No: macros are mostly pure functions from code to code. – coredump Jan 09 '18 at 15:52
  • 3
    Scheme/Lisp macros have only the name in common with C preprocessor macros. – molbdnilo Jan 10 '18 at 07:16

3 Answers3

7

It certainly has nothing to do with Haskell being pure or lazy, on the contrary.

The main reason why macros aren't as common in Haskell is that it's a static, compiled language, thus changing code at runtime isn't possible anyway. Also, it doesn't have quite as simple syntax as Lisps do, so writing compile-time macros is always a bit more cumbersome.

http://hackage.haskell.org/package/template-haskell-2.12.0.0/docs/Language-Haskell-TH.html#t:Exp

Haskell's lazy evaluation and the abstraction capabilities of its strong type system however mean that you simply don't need macros in lots of situations where Scheme programmers would employ them. Basically, you can abstract over the notion of computation itself, which is a lot like macros (just much cooler, if you ask me...).

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • 6
    Certainly I agree that laziness and purity don't matter, and that the simpler syntax of Scheme does matter. I don't really get what this has to do with being static, or compiled, though: macros typically don't produce code at runtime. – amalloy Jan 09 '18 at 19:19
  • Scheme itself has evolved to be better suited to compilation anyway. R5RS `eval` is very weak. Racket has staged imports. People aren't using `apply` as much. – dfeuer Jan 09 '18 at 19:38
  • 1
    I'm not going to downvote, but the static & compiled nature of the language has nothing to do with macros. Racket is statically compiled, & has an extremely rich macro system. – John Clements Jan 11 '18 at 23:53
  • @JohnClements I've not used Racket much, but I recall it as feeling in principle not that different from other Lisps, with the dynamic _types_ facilitating a code-as-data approach. The fact that modern Lisp dialects are able to pre-compile a lot and JIT-optimise much of the rest is great, but IMO that doesn't change the fact that these languages are at least conceptually interpreted languages, whereas Haskell has intentionally a very solid boundary between compile time and run time. – leftaroundabout Jan 12 '18 at 08:47
  • Yes, Racket is dynamic, but its macro system has a very static flavor. And that's quite intentional--it allows for much better compilation. Racket as a whole tends to try its best to prevent expensive dynamic features from slowing down code that doesn't use them. – dfeuer Jan 12 '18 at 10:37
  • I think that the distinction between "compiled" and "interpreted" languages is no longer a real thing at all; consider JavaScript; you may think of it as an "interpreted" language, but there are plenty of JITs that can compile JS to assembly. – John Clements Jan 12 '18 at 18:11
  • @JohnClements that's just a performance optimisation. The point is that the programmer doesn't need to be aware of any JIT to write correct code; the language is _conceptually_ interpreted. Whereas in C++, Haskell or Rust, there's a very fundamental distinction that you know some things are guarenteed to get completely done at compile time, and other things are left to runtime. This is particularly interesting when you're not sure if something will work, but you're sure that if it fails it will already do so at compile time. Makes a lot of testing unnecessary. – leftaroundabout Jan 14 '18 at 11:01
  • I think that when you say "conceptually interpreted," you mean "dynamically typed". Specifically, you say "you're sure that if it falis it will already do so at compile time." I think that the top 30 examples on this list are all going to be type system errors. This is orthogonal to compilation. Also, you might be interested in Typed Racket, a statically typed member of the Racket family, which provides the same guarantees that you mention. – John Clements Jan 14 '18 at 21:50
3

This should help you. Lisp languages' syntax are a lot simpler than other languages and the parser is directly accessible from the language.

Clojure is a type of lisp that is both lazy and can deal with pure code but still has the powerful macros of Lisp.

Axnyff
  • 9,213
  • 4
  • 33
  • 37
1

In addition to the prior answers, I would say that both Haskell and Scheme are largely academic languages, meaning specifically that work on them is driven by researchers, and their particular interests. For these languages, then, those that are interested in Macros are likely to gravitate toward the language with the syntax system (Scheme/Racket/Clojure) whose uniformity (everything is parenthesized) makes macro definitions dramatically easier.

John Clements
  • 16,895
  • 3
  • 37
  • 52