1
votes

I have been trying to think more about what abstraction actually means in functional programming. The very best post I have found that talks the type of language I can understand is the following 4 abstractions. However since I'm a wannabe Clojure programmer I'm wondering what sort of abstractions macros provide. It seems that they fit in stage 2 together with HOF but at the same time they are more then a HOF. I find stage 3 to be related to the Expression problem and would be protocol and multi methods in Clojure. So my question is:

When implementing a macro in a Lisp language what would you say you are abstracting over?

What would stage 3 and 4 be in a Lisp language?

1
Nice question, but this is more suitable fro CSSE. I'd say macros abstract like stage 1 but at compile time. While functions transform values, macros transform code and that code is what actually get run. - Sylwester
I agree with all of the parts of @TimothyBaldridge's answer that I'm qualified to evaluate. I would have just emphasized that they are ways of using Lisp to rewrite Lisp source code. I don't think macros fit into the four abstractions list, since they act prior to evaluation. However, macros might be thought to allow abstraction in this sense: You can use a macro to abstract a pattern that's common to several distinct functions, generating those functions from the macro. This highlights why macros often can (and should) be avoided: HO functions already allow something similar. - Mars

1 Answers

2
votes

I don't really view macros as an abstraction, but more as a compiler hook.

Most languages implement what is known as an Abstract Syntax Tree (or AST). This is a representation of the code of a program in a sort of data structure. Lisp macros expose parts of this AST as data that can be transformed via a macro function. But since lisp programs are themselves data structures, macros tend to be a bit cleaner in lisp programs then they would be in Rust or Scala.

So one could say that macros are simply abstractions of language semantics...but I don't know that I agree with that. One could say that macros are extensions of the lisp compiler, but that's not exactly true either.

As it turns out, macros are quite limited. They can only see a small subsection of the code being compiled. In other words, a macro can't see up the tree, only down. In addition while macros that perform deep inspection of children in the AST are possible (known as deep walking macros) these macros tend to be complex and error prone (just look at the guts of core.async's go or the contents of midje to see how complex these can get). So I hesitate to call them abstractions, perhaps they are, perhaps they are just very limited abstractions.

So I see macros as a weird mix between the more powerful Fexprs (http://en.wikipedia.org/wiki/Fexpr) and the more complete compiler code transforms found in projects like LLVM. They provide a very limited controlled way to transform code at compile time, that's about it.

And in the end it all comes down to the lisp mantra that "code is data is code". If your code is data it makes sense to provide ways to transform it at compile time.