6 ms·
> I guess it's just another example of the usual difference in software design between CL and Scheme programmers. You mean, nitpicking about trivialities ;-) ?
by junke 10y ago
> I guess it's just another example of the usual difference in software design between CL and Scheme programmers.
You mean, nitpicking about trivialities ;-) ?
- davexunit 10y agoYou're joking, right? It's not a trivial matter. I appreciate both design methods (I associate myself with plenty of CL programmers), but I can't hide that I think Scheme made the better design decisions.
- junke 10y ago> You're joking, right? It's not a trivial matter. It is a matter of context. There is a whole blog post full of hard work and you comment about an unhygienic macro. Author said: This is nice and readable. Some folks will dislike the fact that it introduces new variable bindings that are “hidden” in the macro definition, but I like the concision you get from it, especially for a small project like this. This is a small project, the code is deliberately using macros in a way that is regarded as poor style (even in CL), but this is not important here. There is no need to start a flame about single namespaces.
- sigjuice 10y agoCan't similar brevity be achieved by using a special variable called 'chip'?
- junke 10y agoYes, sure (defvar *chip*) (defun memory (&optional (chip *chip*)) (chip-memory chip)) Just binding the variable is enough. If you want to hide this variable as an implementation detail, you can use a macro: (defmacro with-chip (chip &body body) `(let ((*chip* ,chip)) ,@body)) You could also have a symbol-macrolet so that "memory" expands as a call, i.e. "(memory)", but then you would have the same syntax as the above poster wanted to avoid ;-) (except that accesseors already provide setf functions)
- davexunit 10y agoHOLY SHIT I SAID I LIKED THE POST. I have talked to the author on IRC. I was just playing off of what he wrote about certain people not liking the with-chip macro. The amount of downvotes I'm getting is ridiculous.
- progman 10y agoI know both Lisp and Scheme pretty well. Scheme's macros are hygienic, Lisp's macros however are much easier to handle. The hygiene problem can be solved by using (gensym) for local identifiers. Example: http://stackoverflow.com/questions/267862/what-makes-lisp-macros-so-special http://stackoverflow.com/questions/267862/what-makes-lisp-ma...
- kazinator 10y agoTo completely solve the hygiene problem on an academic level, you have to use gensyms for all references generated by the macro, including all function symbols. Lisp macros don't bother doing this because the Lisp-2 separation provides adequate hygiene. Programs which choose to lexically shadow standard functions like cons or list in the function namespace are considered to be sticking a fork in the proverbial toaster, and so that is not handled. That would't work as well in Scheme because the mere presence of a variable called list in the user's code would interefere with a (list ...) function call generated by a macro. Also providing hygiene are packages. If macro-generated code references private symbols in the macro's own package, everything is cool. Packages take care of the problem for nonstandard functions. You just don't use another package's symbols for local functions and variables, and that's that.
- groovy2shoes 10y agoHow are Lisp's macros easier to handle than syntax-rules? On the one hand, you have a function that receives an s-expression, manually deconstructs and transforms the s-expression while (hopefully) carefully, manually aliasing any symbols to avoid inadvertent capture, and constructs a replacement s-expression. On the other hand, you have a pattern-matching facility that automatically takes care of deconstruction and hygiene for you. Yes, syntax-rules is strictly less powerful than defmacro, but in practice it covers the vast majority of use cases very well. I'd also like to mention that avoiding variable capture is only one part of macro hygiene. The other part is referential transparency in the face of shadowing. Common Lisp partly provides this because names in the standard package can't be redefined, but it's still wide open when it comes to other names. Consider this (admittedly contrived, for simplicity) example: (defun square (x) (* x x)) (defmacro hypotenuse (x y) `(sqrt (+ (square ,x) (square ,y)))) ... (let* ((square (make-square s)) (diagonal (hypotenuse s s))) ; ERROR! tried to apply ...) ; #'* to a square! In the expansion of `hypotenuse`, `square` refers to the local variable bound on the line above it, while the macro author clearly intended it to refer to the "global" variable up top. This is a situation that's fairly easy to run into, and horribly confusing when it occurs (especially if the user of the macro didn't write it). Hygiene ensures that the reference to `square` in `hypotenuse` will always refer to the binding of `square` that was in scope at the time the macro was defined, thus avoiding the problem. On its own, `gensym` is necessary but not sufficient for hygiene.