| so, i'm not a CL wizard, but i've spent some time with it. One cool part about macros, the part that really matters, you get to control the order of evaluation. That doesn't sound super interesting, so let's get a little more concrete. Say you want to model option contracts. They can get crazy complicated. most DSLs will have things that are AND like and things that are OR like. In C you're stuck with something like this for the and case: all = 1;
for(int i = 0; i < clause_count; i++){
if(eval(clause[i]) == 0){
all = 0;
break;
}
}
return all;
The key point here is the break. we actually want to stop evaluation of the later parts of the code.with a macro, you just expand out all of the eval'ing of the clauses in place. you can't just map over the list of clauses, because we want the early exit. my lisp is rusty, but i think it'd look kinda like (defmacro optionand (&rest clauses)
`(and ,@(map (lambda (c) (list 'eval c) clauses)))
the gist being, we leverage the built in and to do something like: (and
(eval google-at-700)
(eval oil-at-50))
so you embed right in the language itself, taking advantage of the built in short circuiting of and.in haskell, you can play a very cute game. since functions are lazy, you get full control over evaluation - you don't need a special form to implement if, for example. So, the very cute trick is to make your dsl out of ordinary functions, that use typeclasses for implementation. in the above case eval would be a method in a typeclass. (you can do the very same thing in lisp, it just seems like a bit more effort to carry around the specific implementation of eval, haskell will just figure it out with the typechecker). The thing that's great about the trick, you can write multiple implementations of eval, and not rewrite all your contracts. One implementation could just straight up evaluate it. Another version could do some fuzzier math with variance of the underlying price, and return a gaussian rather than a number. Again, the key is controling the actual evaluation i think there's some bits and pieces about it in _on lisp_ which i think pg made available online.
haskell's bracket function is a great example and would be a nice macro candidate (bracket obtain-resource do-stuff release-resource)
(bracket get-socket talk close-socket) ; for example
no matter what happens in do-stuff, release is always called.it's possible (even easy?) to do scary stuff with controlling the order of evaluation, but when you see code with those complicated breaks and continues, it's often a side effect of not having good macros. edit i learned the haskell trick from Oleg Kiselyov's papers - http://okmij.org/ftp/tagless-final/ He uses it to make an interpreter into a compiler, and very clever stuff with partial evaluation. That guy is really smart. Although pg doesn't call out DSL's specifically, the macro chapter is good. http://unintelligible.org/onlisp/onlisp.html#SEC49 and indeed you can get the whole book here http://www.paulgraham.com/onlisp.html |