From: Max Brieiev <max.brieiev@gmail.com>
To: emacs-devel@gnu.org
Subject: Issues with named-led and pcase inside iter-defun.
Date: Mon, 11 Sep 2023 11:47:17 +0300 [thread overview]
Message-ID: <87leddnlka.fsf@gmail.com> (raw)
Hello,
I've been trying to build some of my code on top of generator.el
library. I've found that functions defined with iter-defun have some
issues with named-let and pcase.
This is a macro I use to wrap iter-defun and advance the iterator to the
first yield expression:
(defmacro co-defun (name args &rest body)
"Define a coroutine. Automatically advance it to the first yield
expression."
(declare (indent defun))
(let ((co-name (gensym (concat (symbol-name name) "-co-"))))
`(progn
(iter-defun ,co-name ,args ,@body)
(defun ,name (&rest passthrough-args)
(let ((co (apply #',co-name passthrough-args)))
(iter-next co)
co)))))
Now, here is a superficial example that involves both named-let and pcase:
(co-defun lazy-sum ()
(named-let sum ((running-sum 0))
(pcase running-sum
((pred (< 10)) running-sum)
(_ (sum (+ running-sum (iter-yield nil)))))))
(setq it (lazy-sum))
(iter-next it 3)
(iter-next it 5)
(iter-next it 7) ; raises (iter-end-of-sequence . 15)
So far so good. But let's make the example a bit more practical:
(co-defun curling-parser/headers (chunk)
"Parse HTTP headers. Returns alist of headers and the remaining data."
(named-let parse-chunk ((chunk chunk) (aheaders (list)))
(pcase chunk
;; header line
((rx line-start
(let name (+ (not ":")))
":"
(* blank)
(let value (+ (not "\r")))
"\r\n"
(let tail (* anything)))
(parse-chunk tail (cons (cons name value) aheaders)))
;; end of headers section
((rx line-start
"\r\n"
(let tail (* anything)))
(list (nreverse aheaders) tail))
;; suspend. Resumes parsing after the next chunk comes in
(_ (parse-chunk (concat chunk (iter-yield nil)) aheaders)))))
;; Send chunks into the coroutine
(setq parser (curling-parser/headers "Content-Ty"))
(iter-next parser "pe: text/plain\r\nCache-Control: no-ca")
(iter-next parser "che\r\n\r\nHello World!")
The above has essentially the same structure as lazy-sum function,
however this code fails with the error:
(void-function cps-internal-yield)
Is this a bug related to iterators in Elisp?
After some trial and error, I found that iter-yield sometimes doesn't
work inside pcase, so I moved it outside of pcase like this:
(named-let parse-chunk ((chunk chunk) (aheaders (list)))
(let ((result (pcase ...)))
(if result
result
(parse-chunk (concat chunk (iter-yield nil)) aheaders))))
But now it started to fail with the same error outside pcase, but inside
named-let!
So my question is how do I work around this? There is no obvious way to
tell whether iter-yield will succeed or fail inside pcase/named-let
construct. Is it a fundamental limitation of iterators or just a bug
that needs to be fixed?
I have rewritten my code with a plain while loop, and it works without
issues, but I like named-let/pcase approach much more.
next reply other threads:[~2023-09-11 8:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-11 8:47 Max Brieiev [this message]
2023-09-12 0:01 ` Issues with named-led and pcase inside iter-defun Michael Heerdegen
2023-09-12 8:55 ` Max Brieiev
2023-09-13 4:21 ` Michael Heerdegen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87leddnlka.fsf@gmail.com \
--to=max.brieiev@gmail.com \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.