From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: continuation passing in Emacs vs. JUST-THIS-ONE Date: Thu, 16 Mar 2023 23:08:25 -0400 Message-ID: References: <627090382.312345.1678539189382@office.mailbox.org> <87sfe7suog.fsf@gmail.com> <1c6fedae-10b4-5d97-5036-eaa736e1b816@gmail.com> <87mt4c6xju.fsf@logand.com> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="8659"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: Jim Porter , Karthik Chikmagalur , Thomas Koch , "emacs-devel@gnu.org" To: Tomas Hlavaty Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Fri Mar 17 04:09:15 2023 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pd0Sw-00024n-My for ged-emacs-devel@m.gmane-mx.org; Fri, 17 Mar 2023 04:09:15 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pd0SJ-00020S-EC; Thu, 16 Mar 2023 23:08:35 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pd0SH-000203-EF for emacs-devel@gnu.org; Thu, 16 Mar 2023 23:08:33 -0400 Original-Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pd0SF-0005cO-DY for emacs-devel@gnu.org; Thu, 16 Mar 2023 23:08:33 -0400 Original-Received: from pmg2.iro.umontreal.ca (localhost.localdomain [127.0.0.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id B78CA80658; Thu, 16 Mar 2023 23:08:28 -0400 (EDT) Original-Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id C3EDA80012; Thu, 16 Mar 2023 23:08:26 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca; s=mail; t=1679022506; bh=96cHBSgj4sj2wSlDTinSO5A+1gM4Bs12S/e97aNBUUg=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From; b=cZ8XU33pM0OS67fRXqoiHotXoHMObwBqRuykgumuSh2q1qBO+k8Wg1gsHZV/v+G2L 0yK8FdjQ11jxtmr5oI3zNmI775UUcYzBBePNFV0STpZ+V1kyWYztn8zTz9ktxWbn3y QlVq3NZMwH2O7OKmwGQINNKS/ro/Jp1qi8OqnoRq166/6+PJpoIM+NA3yyLgcbmdmo hCEPFPQcWfRdEoZBpOGcdZX6Q2M9V9cPeQj1ONpe6FxArq23wC7SypRwROq5UdJfrW xi038vHValemlSVJr66nW76Mmr/ABQ0V0DJrPxnM5mO5TLGrLDmOVRMB3sqCov92MH PCeb8pdrycCLQ== Original-Received: from pastel (unknown [216.154.34.24]) by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id 89DA0123258; Thu, 16 Mar 2023 23:08:26 -0400 (EDT) In-Reply-To: <87mt4c6xju.fsf@logand.com> (Tomas Hlavaty's message of "Fri, 17 Mar 2023 01:17:41 +0100") Received-SPF: pass client-ip=132.204.25.50; envelope-from=monnier@iro.umontreal.ca; helo=mailscanner.iro.umontreal.ca X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:304535 Archived-At: >> ;; (futur-let* >> ;; (exitcode <- (futur-process-make :command cmd :buffer t)) >> ;; (out (buffer-string)) ;; Get the process's output. >> ;; (cmd2 (build-second-arg-list exitcode out)) >> ;; (otherexit <- (futur-process-make :command cmd2 :buffer t))) >> ;; (futur-pure (buffer-string))) > > Seems like beautiful lisp code has no futur. :-) BTW the above code can't work right now. Part of the issue is the management of `current-buffer`: should the composition of futures with `futur-let*` save&restore `current-buffer` to mimic more closely the behavior one would get with plain old sequential execution? If so, should we do the same with `point`? What about other such state? > There is something very ugly about this code. > It looks like assembly, 1 dimensional vertical code. > It is hard to see the structure of the code and what it actually does. > I do not think it is practical to write non-trivial code in this style. :-) > Nice lisp code is usually 2 dimensional, > with indentation and top-left to bottom-right direction. > It is usually much clearer to see what is an argument to what > based on the position in the syntax tree. > > Is it possible to make the syntax more structured (lispy)? > Meaning tree-like, not list-like? > Something in the spirit of: > > (futur-progn > (futur-process-make > :command (futur-let ((exitcode (futur-process-make > :command (build-arg-list) > :buffer t))) > (build-second-arg-list exitcode (buffer-string))) > :buffer t) > (buffer-string)) The `futur-progn` is just: (defmacro futur-progn (form &rest forms) (if (null forms) form `(futur-let* ((_ ,form)) (futur-progn ,@forms)))) As for passing the result of `futur-let` to `:command` it just requires writing `futur-process-make` in a way that is tolerant of this `:command` arg being a future rather than a string, which should be fairly easy (it's basically always easy when done within a function which itself returns a future). > or would it need some fancy syntax rewriting like other async/cps > syntax rewriting libraries? I don't think so, no. But you would need fancy rewriting if you wanted to allow (concat foo (futur-let* (...) ...)) But as you point out at the beginning, as a general rule, if you want to avoid rewritings in the style of `generator.el`, then the code will tend to feel less like a tree and more "linear/imperative/sequential", because you fundamentally have to compose your operations "manually" with a monadic "bind" operation that forces you to *name* the intermediate value. > Second question: I see that futur-wait blocks the whole Emacs due to > the while loop. How can one use futur without blocking Emacs? Don't use `futur-wait` and instead use `futur-let*`. IOW: instead of waiting, return immediately a future. > Last question: How would similar functionality be implemented > using futur? Good question. To a large extent I guess it could be implemented in basically the same way: you'd use futures only for the timer part of the code, and leave the process's output to fill the buffer just like you do. I think the difference would be very small and cosmetic like replacing (defun stream-pull-in-background (stream &optional secs repeat) (let (timer) (setq timer (run-with-timer (or secs 1) (or repeat 1) (lambda () ;;(message "@@@ polling!") (unless (funcall stream) (cancel-timer timer))))))) with something like: (defun stream-pull-in-background (stream &optional secs repeat) (futur-run-with-timer (or secs 1) (lambda () ;;(message "@@@ polling!") (when (and (funcall stream) repeat) (stream-pull-in-background stream secs repeat))))) The only benefit I could see is that it returns a future, i.e. a kind of standardized representation of that async computation so the caller can use things like `futur-wait` or `futur-let*` without having to care about whether the function is using timers or something else. And, there's also the benefit of standardized error-signaling. Stefan