From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Jean Abou Samra Newsgroups: gmane.lisp.guile.user Subject: Re: for with break and continue Date: Sun, 4 Sep 2022 12:43:58 +0200 Message-ID: <89d7a30c-9a36-00b9-49d1-a28b0d776ce3@abou-samra.fr> References: Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="18180"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.2.0 To: Damien Mattei , guile-user Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Sun Sep 04 12:44:22 2022 Return-path: Envelope-to: guile-user@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 1oUn70-0004aP-JD for guile-user@m.gmane-mx.org; Sun, 04 Sep 2022 12:44:22 +0200 Original-Received: from localhost ([::1]:37270 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oUn6z-0003AL-Jr for guile-user@m.gmane-mx.org; Sun, 04 Sep 2022 06:44:21 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:54738) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oUn6n-0003AD-Ci for guile-user@gnu.org; Sun, 04 Sep 2022 06:44:09 -0400 Original-Received: from mout.kundenserver.de ([212.227.17.10]:39453) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oUn6l-0003hd-1h for guile-user@gnu.org; Sun, 04 Sep 2022 06:44:08 -0400 Original-Received: from [172.20.10.4] ([37.167.83.182]) by mrelayeu.kundenserver.de (mreue106 [212.227.15.184]) with ESMTPSA (Nemesis) id 1Ml72g-1pDnYm1I5s-00lRHy; Sun, 04 Sep 2022 12:44:04 +0200 Content-Language: en-US In-Reply-To: X-Provags-ID: V03:K1:zfJs7rO/yKcZ2QKzvQfLW/CXAyNcgsjgkeMygp0sEKQMfKJTI62 0PV+OGnkE2IE35rgTtUJjc99afE/a4a22nogwUI7miBJcT8CpweehdzcFlO0jkGdMcOuXCV lXEbtj2OXAN/6yNFipecow6msiaEUSpEwDYkskKejkCaUtJuw+XEEijThiStBZmZMkjgwp6 BOcczB3Tipl8j+YTjgEkg== X-UI-Out-Filterresults: notjunk:1;V03:K0:qMC11PZAGc8=:C8X/wHR7LugkkvynMt5sCY R8BM51JtaGejMtHOKFPSCzGh46e8mZEsXTtkG/Ef2vf0cxWsEJeortqlZ966/0taQ9jAyk0M8 jF01RqMCOwnZqYWQq4ZAV0nb71Xq8g5QTTxFRUPLvo/GKN8N+X61+b1ryNV35HhujFBHkeHS9 UfBKCPHYGEHw9CSwBij0cK4FVvgF47FnzN52tqOAtFR5+3ntVxdfzntS/Xph52tWwsQlj5y6n FGOqgJTI3j8ZQ4D8VnEV2zhNHcQ1kuIfhUjZOqNoSe3yu03MZvZf+CGM0UeN/LCaMLXx7RhzX iIsxo+hbop+urf7VINaOeK0yaBUmUlLO5hgi/SKTDDPJfH+1b/DAuOH+x+iBNERRjGhsw2IG8 raSk/RvE82U039XPQ3O1rV3Wbt/gvbbm939Q0wl5TMDl5VUjxddRSMR2HURNWqkYFLBJhsG6I 4yZ+T0bgC4dMdQznnkro8iiHyzVyhxQ5FWaysS4zTTVcjXh5vfNUGZT3v4PxnfiXoVG5z38sc 3ktfvjVxCA9C4KsKNeQqWJMT0Qipbt5/GryW7euIbe77RePCKwSgUQRnDazX/nUhW2HhsCJ7A PvEXDP5V9PY1zWNWiIbocUIswFjZSXOEfBJVvJwIBELz8ZsFdIOr8B5iOjRhcVzIE7R7rN02d PBVzsUiEw+2EDTZA/89sTWSlUhdNKcVXknm4aIIvsPmyqNCHZgnSYfev8PRMJsMWtvGgghUpF XdgjGp7VMG83zVC5Ye0sJ0O1LpG62n6j+9b88Ddm3/DArWiXzuidsjCYdyOncxPSJc/2DA3G Received-SPF: none client-ip=212.227.17.10; envelope-from=jean@abou-samra.fr; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, NICE_REPLY_A=-0.001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.io gmane.lisp.guile.user:18564 Archived-At: Le 04/09/2022 à 11:54, Damien Mattei a écrit : > i try to make a for with break and continue the way C language do it, i > works with break but if i add a continue feature i then loose the break > feature, here is my code: > (define-syntax for/bc > > (lambda (stx) > (syntax-case stx () > ((kwd (init test incrmt) body ...) > > (with-syntax > ((BREAK (datum->syntax #'kwd 'break))) > > #'(call/cc > (lambda (escape) > (let-syntax > ((BREAK (identifier-syntax (escape)))) > init > (let loop () > (when test > > (with-syntax > ((CONTINUE (datum->syntax #'kwd 'continue))) > > #'(call/cc > (lambda (next) > (let-syntax > ((CONTINUE (identifier-syntax (next)))) > body ...))) > > incrmt > (loop)))))))))))) The problem is with the meta level vs. the expanded output level. You have two nested levels of #' . This (with-syntax ((CONTINUE ...)) ...) is part of the expanded output, it doesn't run when your macro is expanded. The body of the (expanded) loop just returns a syntax object. That's not what you want. Here's a definition that works: (define-syntax for/bc   (lambda (stx)     (syntax-case stx ()       ((kwd (init test incrmt) body ...)        (with-syntax ((BREAK (datum->syntax #'kwd 'break))                      (CONTINUE (datum->syntax #'kwd 'continue)))          #'(call/cc             (lambda (escape)               (let-syntax ((BREAK (identifier-syntax (escape))))                 init                 (let loop ()                   (when test                     (call/cc                      (lambda (next)                        (let-syntax ((CONTINUE (identifier-syntax (next))))                          body ...)))                       incrmt                       (loop))))))))))) (let ((i #f))   (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))     (when (< i 5)       continue)     (when (> i 9)       break)     (display i)     (newline))) You could also use quasisyntax (#` and #,) to get the same effect: (define-syntax for/bc   (lambda (stx)     (syntax-case stx ()       ((kwd (init test incrmt) body ...)        #`(call/cc           (lambda (escape)             (let-syntax ((#,(datum->syntax #'kwd 'break)                           (identifier-syntax (escape))))               init               (let loop ()                 (when test                   (call/cc                    (lambda (next)                      (let-syntax ((#,(datum->syntax #'kwd 'continue)                                    (identifier-syntax (next))))                        body ...)))                   incrmt                   (loop)))))))))) That said, I would recommend using syntax parameters for break and continue. They're cleaner, since they can be rebound by the user. Also, you can use let/ec from (ice-9 control) instead of call/cc. It's more efficient because it doesn't need to actually reify the whole environment, since an escape continuation is upwards-only (it can be used inside the expression to escape it, but it can't be used outside to reinstate its context). (use-modules (ice-9 control)) (define-syntax-parameter break   (lambda (sintax)     (syntax-violation 'break "break outside of for/bc" sintax))) (define-syntax-parameter continue   (lambda (sintax)     (syntax-violation 'continue "continue outside of for/bc" sintax))) (define-syntax-rule (for/bc (init test increment) body body* ...)   (begin     init     (let/ec escape       (syntax-parameterize ((break (identifier-syntax (escape))))         (let loop ()           (when test             (let/ec next               (syntax-parameterize ((continue (identifier-syntax (next))))                 body body* ...))             increment             (loop))))))) (let ((i #f))   (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))     (when (< i 5)       continue)     (when (> i 9)       break)     (display i)     (newline))) And here's an example showing the benefits of syntax parameters. Add at the beginning of the code above: (define-module (for)   #:export (break continue for/bc)) In the same directory, put a file rename.scm containing: (use-modules ((for)               #:select ((break . for-break) continue for/bc))              (srfi srfi-1) ; contains a break procedure              (ice-9 receive)) (let ((i #f))   (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))     (receive (before after)       (break (lambda (x)                (> x 5))              (iota i))       (when (pair? after)         for-break)       (display i)))) And run as guile -L . rename.scm As you can see, syntax parameters enable the code to use 'break' for something else. A final note: are you aware of the existence of 'do' in Scheme? Most cases of a C for loop can be written elegantly using do. https://www.gnu.org/software/guile/manual/html_node/while-do.html Regards, Jean