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---
Their differences are
head-response: (article-headers (parse-article a))
body-response: (article-body (parse-article a))
Julieta Shem <jshem@yaxenu.org> writes:
I've got two procedures that are nearly identical. They're only
different in the :data-argument in make-response.
...
Is this the case for a macro? What do you advise? Thank you!
A macro? Why? What's wrong with:
(defun foobar (r g i get-data)
(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 get-data (parse-article a))))))))
Julieta Shem <jshem@yaxenu.org> writes:
That's pretty simple. Thanks. That's what I'm going to do here. I'll
leave the macro for when it's really needed --- learning to distinguish
when they're needed and when they're not.
The #2 trap that novice Lisp programmers fall into is using macros when
they don't need to. A novice that thinks they need to define a macro is probably wrong.
The #1 trap is calling EVAL. A novice that thinks they need to call
EVAL is always wrong.
On 2024-01-13, Julieta Shem <jshem@yaxenu.org> 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.
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)))
:data (article-part (parse-article a))
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 403 |
Nodes: | 16 (2 / 14) |
Uptime: | 43:28:28 |
Calls: | 8,407 |
Calls today: | 2 |
Files: | 13,171 |
Messages: | 5,905,019 |