Prev: local-time on Clozure CL windows vista 64 Can't resolve foreign symbol "gettimeofday"
Next: DEFSTRUCT and lexical environment
From: Kaz Kylheku on 7 Oct 2009 20:50 On 2009-10-07, ????????? <girzel(a)gmail.com> wrote: > I'm trying to write a macro which returns macros (I've been reading > the relevant bits of On Lisp), and running into nested backquote > problems. > > The goal is a macro that creates macros that validates or alters > values. A couple of very simple examples: > > (val-macro between (val x y) > (and (> val x) (< val y)) > ("%s is not between %s and %s" val x y)) Lisp format doesn't have %s. Are you really working in Common Lisp or some dialect which has a C-like formatting function? > (defmacro defval (name arg-list predicate error-clause) > `(defmacro ,name (&rest args) > `(let ((result (lambda arg-list predicate args))) > (if result > (values t (first args)) > (values nil (format nil error-clause)))))) What's the point of simply returning the error message as a string? Wouldn't it make more sense to signal a condition? How will this string value be used, if it is generated? It seems error prone; what if the surrounding code is not prepared to deal with a string value? Your out-of-range catch turns into a type mismatch. To test your program for the correct handling of all these situations, you will have to have a unit test which trigger all of these exceptional conditions, everywhere they occur. It's easier to have confidence that that one central error handler is working, even without 100% coverage. Also, it's not clear what values are substituted into the string. Suppose the programmer writes this: (between temperature low high) Do you want the string to be: "TEMPERATURE is not between LOW and HIGH" or do you want it to be: "TEMPERATURE is not between -10 and 30" or even: "-15 is not between -10 and 30" Without settling these questions, there is no one correct way to write this stuff.
From: Vassil Nikolov on 7 Oct 2009 21:14 I ought to add the following: That backquoting _can_ be nested does not mean it _has_ to be: apart from the purposes of learning and exercising, deeply nested backquoting may get too unwieldy. Illustrated with the same problem, here is another approach that scales better for more complicated syntax (though perhaps unnecessary for simple macros), where we define explicit form- and subform-producing functions which do the work, while each DEFMACRO form itself is kept as simple as a single function call. (It is all in the eyes ^W construction of sexprs...) Note how the program below has no nested backquoting (comparing it to the equivalent "standalone" DEFMACRO form posted earlier in this thread, which has). (defun make-assert-form (test places report-data) `(assert ,test (,@places) ,@report-data)) (defun make-assertion-test (test-params test-form test-args) `((lambda (,@test-params) ,test-form) ,@test-args)) (defun make-validator-assertion (test-params test-form test-args report-data) (make-assert-form (make-assertion-test test-params test-form test-args) (list (first test-args)) report-data)) (defun make-validator-definition (name params test report-datum report-args) `(defmacro ,name (,@params) (make-validator-assertion ',params ',test (list ,@params) (list ',report-datum ,@report-args)))) (defmacro define-validator (name params test (report-datum &rest report-args)) (make-validator-definition name params test report-datum report-args)) (define-validator validate-between (val x y) (and (> val x) (< val y)) ("~S is not between ~S and ~S" val x y)) ;; to try it out e.g.: ;; (macroexpand-1 '(validate-between n a b)) ;; (let ((n 20)) (validate-between n 1 10)) ---Vassil. -- "Even when the muse is posting on Usenet, Alexander Sergeevich?"
From: Eric on 9 Oct 2009 00:32
It's great to see some alternate approaches here -- giving users a little more flexibility to, say, simply write their own function and then feed that function to a simpler macro would probably be more flexible, though I also like the composition of several smaller macros. This is a learning exercise, but also practical -- I'm trying to make a small library for validating user input into HTML forms, hence the errors returned as strings. Thanks to all for the food for thought. Eric |