Live data from Hacker News

Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

blog.metaobject.com

21–30 of 114 posts

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#21
post #16

Earlier quoted context omitted.

I don't think what I wrote is a FEXPR, which doesn't evaluate the result of the function call. I'm having a hard time parsing what you wrote or any of the sources you linked in such a way that says the semantics of macros differs from what I wrote (certainly the implementation gets a lot more complex and there are subtleties).

That's why I wrote 'more like'. Given that you haven't defined any semantics of your operators, it's more like a guess. Not sure if this helps you. But let's define a macro A: CL-USER 32 > (defmacro a (b c) (print (list :macro-expansion b c)) (list 'print (list 'quote (list :runtime :b b :c c)))) A This macro does two things: it prints something at macro expansion time and then generates some code it returns as a val…

But an infix transform does delay the evaluation of expressions you've passed to it. Eg (infix (avg b) * (sgn a)).

And most practical uses of macros involve passing in expressions that will be later evaluated verbatim, e.g. (time (reduce + (range 100)))

I was only intending responding to this:

"That's a common misconception that Lisp macros are mostly used to 'delay' evaluation."

Which just seems to me confuses the matter in response to the article that was posted. At a very low level, macros operate by having the evaluation of their arguments delayed. At a higher level, they're used to implement sugared forms which usually contain valid code (though not necessarily code that makes sense in isolation).

I know you're very experienced with lisp, and I'm not trying to correct you technically, but to me this stuff only clicked when implementing a metacircular evaluator and learning when and how to perform evaluation. The blog post to me reads like the author was going through a similar process.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#22
Scala has implemented support for async-await syntax using its experimental macros: https://docs.scala-lang.org/sips/async.html

Just an example of how powerful macros can be.

They also have an example in their docs about implementing printf using a macro so that formatting parameters are typechecked.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#23
post #16

Earlier quoted context omitted.

That's why I wrote 'more like'. Given that you haven't defined any semantics of your operators, it's more like a guess. Not sure if this helps you. But let's define a macro A: CL-USER 32 > (defmacro a (b c) (print (list :macro-expansion b c)) (list 'print (list 'quote (list :runtime :b b :c c)))) A This macro does two things: it prints something at macro expansion time and then generates some code it returns as a val…

But an infix transform does delay the evaluation of expressions you've passed to it. Eg (infix (avg b) * (sgn a)). And most practical uses of macros involve passing in expressions that will be later evaluated verbatim, e.g. (time (reduce + (range 100))) I was only intending responding to this: "That's a common misconception that Lisp macros are mostly used to 'delay' evaluation." Which just seems to me confuses the m…

> But an infix transform does delay the evaluation of expressions you've passed to it. Eg (infix (avg b) * (sgn a)).

It doesn't 'delay' anything. It just rewrites at compile time

   (infix (avg b) * (sgn a))
into

   (* (avg b) (sgn a))
That's all. At runtime only the rewritten statement will be executed.

> At a very low level, macros operate by having the evaluation of their arguments delayed

Not at all. The main purpose of macros is to compute code from arbitrary expressions at compile time. There is no 'delay' -> it's mostly about rewriting expressions at compile time.

> implementing a metacircular evaluator and learning when and how to perform evaluation.

You can build a macro expansion phase into an interpreter. That's what Lisp interpreters do. But the main purpose of macros is to enable code transformations at compile time and thus only to have a cost at compile time, not at runtime. In an interpreter the macro expansions would also happen at runtime and have a cost there. But Lisp compilers are popular and to make the most out of code transformations at compile time, the idea of macro and their expansion at compile-time was introduced. Thus one gets for example new embedded languages, without the need to parse them at runtime.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#28
post #2

That's a common misconception that Lisp macros are mostly used to 'delay' evaluation. What Smalltalk calls 'blocks' are just (anonymous) functions in Lisp. Books like SICP explain in detail how to use that for delayed evaluation in Lisp/Scheme: https://mitpress.mit.edu/sites/default/files/sicp/full-text/...

> misconception that Lisp macros are mostly used to 'delay' evaluation. It was in the examples. No generalization to all of LISP was made or intended, though it would be interesting to make a survey study of actual macro usage by developers. It is also clear that you actually need the delay-evaluation mechanism in order to get something like "if" out of the language and into the library. > what Smalltalk calls 'block…

> It is also clear that you actually need the delay-evaluation mechanism in order to get something like "if" out of the language and into the library.

In a functional programming language one can just use functions.

  (defun l-true (a b) a)
  (defun l-false (a b) b)

  (defun l-if (f a b) (funcall f a b))
True is a function, false is a function and if is a function.

Now we can do conditional execution:

  CL-USER 57 > (l-if #'l-true 1 2)
  1

  CL-USER 58 > (l-if #'l-false 1 2)
  2

  CL-USER 59 > (funcall (l-if #'l-true
                              (lambda () (print 'true-case) nil)
                              (lambda () (print 'false-case) nil)))

  TRUE-CASE 
  NIL

But Lisp doesn't do that. It provides one conditional as a primitive.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#29
post #16

Earlier quoted context omitted.

I don't think what I wrote is a FEXPR, which doesn't evaluate the result of the function call. I'm having a hard time parsing what you wrote or any of the sources you linked in such a way that says the semantics of macros differs from what I wrote (certainly the implementation gets a lot more complex and there are subtleties).

That's why I wrote 'more like'. Given that you haven't defined any semantics of your operators, it's more like a guess. Not sure if this helps you. But let's define a macro A: CL-USER 32 > (defmacro a (b c) (print (list :macro-expansion b c)) (list 'print (list 'quote (list :runtime :b b :c c)))) A This macro does two things: it prints something at macro expansion time and then generates some code it returns as a val…

While experienced lispers already know this, it may not be clear to everyone that in Common Lisp "compile time" routinely happens repeatedly in a running image. cl-ppcre[1] relies heavily on this. It can take a regexp pattern as a runtime input and compile a recognizer down to machine code on the fly. This technique gets used routinely.

Edit: In fact, I strongly suspect that this resulting unsuitability of Lisp for proprietary code played a major role in its commercial failure before the widespread advent of services.

[1] https://edicl.github.io/cl-ppcre/

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#30
post #29
post #16

Earlier quoted context omitted.

That's why I wrote 'more like'. Given that you haven't defined any semantics of your operators, it's more like a guess. Not sure if this helps you. But let's define a macro A: CL-USER 32 > (defmacro a (b c) (print (list :macro-expansion b c)) (list 'print (list 'quote (list :runtime :b b :c c)))) A This macro does two things: it prints something at macro expansion time and then generates some code it returns as a val…

While experienced lispers already know this, it may not be clear to everyone that in Common Lisp "compile time" routinely happens repeatedly in a running image. cl-ppcre[1] relies heavily on this. It can take a regexp pattern as a runtime input and compile a recognizer down to machine code on the fly. This technique gets used routinely. Edit: In fact, I strongly suspect that this resulting unsuitability of Lisp for p…

That's not a Common Lisp specific thing. The first Lisp compiler in 1962 was already written and running inside Lisp.

Whether the compiler runs inside an 'image' or in some batch mode is also not important for macros.

Post reply on HN