On 2024-01-13, Julieta Shem <
[email protected]> wrote:
I've got two procedures that are nearly identical. They're only
different in the :data-argument in make-response. (I've simplified them
a bit to make them short and easy to read, but they're very close to the originals.)
--8<---------------cut here---------------start------------->8---
(defun head-response (r g i)
(let ((a (handler-case (fetch-article g i)
(sb-ext:file-does-not-exist (c)
(error-response c)))))
(cond ((typep a 'response) a)
(t (prepend-response-with
(format nil "~a ~a" i (extract-mid a))
(make-response :multi-line 'yes :code 200
:request r :data (article-headers (parse-article a))))))))
(defun body-response (r g i)
(let ((a (handler-case (fetch-article g i)
(sb-ext:file-does-not-exist (c)
(error-response c)))))
(cond ((typep a 'response) a)
(t (prepend-response-with
(format nil "~a ~a" i (extract-mid a))
(make-response :multi-line 'yes :code 200
:request r :data (article-body (parse-article a))))))))
--8<---------------cut here---------------end--------------->8---
Here is one (untested) possibility:
(defmacro prepare-article-response (r g i avar expr)
`(let ((,avar (handler-case (fetch-article ,g ,i)
(sb-ext:file-does-not-exist (c)
(error-response c)))))
(cond ((typep ,avar 'response) ,avar)
(t (prepend-response-with
(format nil "~a ~a" ,i (extract-mid ,avar))
(make-response :multi-line 'yes :code 200
:request ,r :data ,expr))))))
(defun head-response (r g i)
(prepare-article-response r g i a (article-headers (parse-article a))))
(defun body-response (r g i)
(prepare-article-response r g i a (article-body (parse-article a))))
The redundant calls to parse-article seem wasteful, but that's an organizational issue beyond the present scope.
Caveats: the i argument is evaluated twice, and r g i are not
evaluated in the order they appear in the macro argument list.
If this is only as a jig for writing functions like the above, where
those expressions are symbols referring to arguments, that's not a
problem.
We can write the macro by passing a lambda into a function:
(defun prepare-article-response-impl (r g i fun)
(let ((a (handler-case (fetch-article g i)
(sb-ext:file-does-not-exist (c)
(error-response c)))))
(cond ((typep a 'response) a)
(t (prepend-response-with
(format nil "~a ~a" i (extract-mid a))
(make-response :multi-line 'yes :code 200
:request r :data (funcall fun a)))))))
(defmacro prepare-article-response (r g i avar expr)
^(prepare-article-response-impl ,r ,g ,i (lambda (,avar) ,expr)))
defuns are as before. The order of evaluation issues disappear,
sine we are no inseting the argument expressions r g i into
a function argument list.
--
TXR Programming Language:
http://nongnu.org/txr
Cygnal: Cygwin Native Application Library:
http://kylheku.com/cygnal
Mastodon: @
[email protected]
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)