3 ms·
I know you said "quick and dirty", but the unhygienic variable capture on those args is making my parens twitch. :) This was a nice explanation.
by gmfawcett 5y ago
I know you said "quick and dirty", but the unhygienic variable capture on those args is making my parens twitch. :)
This was a nice explanation.
- kazinator 5y agoThey have to be unhygienic because the code makes references to those specific symbols. We need to bind each of those symbols to a nil and t constant against different copies of that code, thereby shadowing the original variable, based on whose value the decision is made which way to bind the shadow. Our macrology does not introduce any hidden variables of its own; we don't have anything to hide behind gensyms. We have not even evaluated any argument material twice.
- gmfawcett 5y agoOf course you're right. I read your code again, and I stand corrected. Well done.
- phoe-krk 5y agoYou don't need hygiene (WITH-GENSYMS and so on) in Common Lisp macros in two situations: when you do not introduce any new bindings and when you only introduce bindings that the user is allowed to name themself. That's why the following code: (with-open-file (my-super-stream #p"/tmp/foo" ...) ...) Can expand into something like this: (let ((my-super-stream (open #p"/tmp/foo" ...))) ...) Note that the variable name, MY-SUPER-STREAM, is provided by the user, so if there is any variable capture/shadowing present then it is of the user's own making and they can reap the benefits and costs of doing so.
- gmfawcett 5y agoI agree, and I missed the fact that kazinator's code was introducing new variables. I'm always happy to be wrong in public for didactic purposes. :)