|
|
|
|
|
by curist
1712 days ago
|
|
May be unrelated, but that's why I prefer the way JS approach this kind of problem: JS doesn't have macros. People use callback function to achieve almost the same thing function doTexture(texture, fn) {
beginTextureMode(texture)
fn()
endTextureMode()
}
doTexture(myTexture, () => {
drawCircle()
drawRectagle()
})
At the cost of being more verbose, we get the benefit of one thing less to learn; and simplicity is a powerful feature IMO.I guess why this is less popular in lispy languages is because 1. macro
2. callback functions introduce more indent levels :(
|
|
There's a QoL difference here with macros - writing out those lambdas can become annoying. That said, the "good style" rule in (Common) Lisp is to prefer lambda-forms in such cases - i.e. cases where the macro parameters are a block of code to be mostly run straight.
In fact, a common pattern for with-macros (of which doTexture would be an example), is the call-with pattern. Example from some random project of mine:
Which is then used like: All the macro does is, upon expansion, package the code block into a lambda, and passing it to a function call-with-logging-conditions, that does the actual work. So it's like your example, except I don't have to write the lambda myself. This is a trivial case; commonly, macros might accept additional arguments that they process, but eventually they'd still wrap their input body argument in a lambda and expand to a function call with said lambda as argument.A better use of macros, which you can't replicate in JavaScript[0], would be if you wanted to do something like:
And have it expand - at compile time - to: However silly this looks, this kind of code generation is (one of the main reasons) why you need macros.--
[0] - Well, you can if you have a toolchain. Babel is essentially a macro engine for JavaScript, but you can only use it at build time.