From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: adriano Newsgroups: gmane.lisp.guile.user Subject: Re: return macro Date: Thu, 30 Sep 2021 05:37:35 +0200 Message-ID: <84359060abff196e59ae99c28dda37f8ac4b56ae.camel@riseup.net> References: <1142492b-16bf-7181-8d93-38bfc2d3c748@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="31886"; mail-complaints-to="usenet@ciao.gmane.io" To: guile-user Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Thu Sep 30 05:38:02 2021 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 1mVmtW-000841-GI for guile-user@m.gmane-mx.org; Thu, 30 Sep 2021 05:38:02 +0200 Original-Received: from localhost ([::1]:46576 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mVmtU-00072b-NY for guile-user@m.gmane-mx.org; Wed, 29 Sep 2021 23:38:00 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:60362) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mVmtG-0006yJ-5P for guile-user@gnu.org; Wed, 29 Sep 2021 23:37:46 -0400 Original-Received: from mx1.riseup.net ([198.252.153.129]:55436) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mVmtD-00040b-MG for guile-user@gnu.org; Wed, 29 Sep 2021 23:37:45 -0400 Original-Received: from fews2.riseup.net (fews2-pn.riseup.net [10.0.1.84]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "mail.riseup.net", Issuer "R3" (not verified)) by mx1.riseup.net (Postfix) with ESMTPS id 4HKf851lvvzDyQ6; Wed, 29 Sep 2021 20:37:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=riseup.net; s=squak; t=1632973061; bh=dhyR3n/Q9FcxefBHvHY5ocppFpoZjhLmjzDnlCQCXRg=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=Kg+fsx4GYt89PDj/va9Gdg/AIfH02oz0orEuPtycYyueyqxzbl+3ej0CKEsyzxM1l xBOK4SpPAcKOCfqcYbOg/bHBPgL8efeHPfC3F3isr0Hg6ku1U2oKIdXDU0DhZluQUy r2tq2WZL3mm5uKc+Qk7lBY3wFV7DLvzYR9sqyIcc= X-Riseup-User-ID: EB525E259B240461E8F792C068D29CC1C03C55D732F644A415FE386784E4EF40 Original-Received: from [127.0.0.1] (localhost [127.0.0.1]) by fews2.riseup.net (Postfix) with ESMTPSA id 4HKf840146z1yTD; Wed, 29 Sep 2021 20:37:39 -0700 (PDT) In-Reply-To: <1142492b-16bf-7181-8d93-38bfc2d3c748@gmail.com> Received-SPF: pass client-ip=198.252.153.129; envelope-from=randomlooser@riseup.net; helo=mx1.riseup.net X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.23 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:17787 Archived-At: Il giorno lun, 28/06/2021 alle 03.15 +0200, Taylan Kammer ha scritto: > On 28.06.2021 01:10, Damien Mattei wrote: > > hi, > > > > i wanted to create a macro that is used like a function definition > > and > > allow return using call/cc: > > > > (define-syntax def > > (syntax-rules (return) > > ((_ (name args ...) body body* ...) > > (define name (lambda (args ...) > > (call/cc (lambda (return) body body* ...))))) > > ((_ name expr) (define name expr)))) > > > > unfortunaly i got error: > > > > scheme@(guile-user)> (def (test x) (cond ((= x 3) 7) ((= x 2) > > (return 5)) > > (else 3))) > > ;;; :2:42: warning: possibly unbound variable `return' > > scheme@(guile-user)> (test 2) > > ice-9/boot-9.scm:1685:16: In procedure raise-exception: > > Unbound variable: return > > > > > > any idea? > > Hi Damien, > > This is because of the "hygiene" rule of Scheme, where the notion of > "lexical > scope" is taken very seriously: for an identifier to be bound, it > must be > visible in the lexical (textual) surroundings where it has been > bound. > > So for instance, in the following example code: > >   (def (test x) >     (cond >      ((= x 3) (return 7)) >      ((= x 2) (return 5)))) > > We can't see a binding for "return" anywhere in the text, therefore > it cannot > be bound. > > This is good "default" behavior because it makes code more flexible > and easier > to understand. > > An easy way of overcoming this issue is to let the user explicitly > name the > return identifier however they like: > >   (define-syntax def >     (syntax-rules () >       ((_ (name ret arg ...) body body* ...) >        (define (name arg ...) >          (call/cc (lambda (ret) body body* ...)))))) > > Now you could define: > >   (def (test return x) >     (cond >      ((= x 3) (return 7)) >      ((= x 2) (return 5)))) > > Or for instance: > >   (def (test blubba x) >     (cond >      ((= x 3) (blubba 7)) >      ((= x 2) (blubba 5)))) > > However, sometimes you're sure that you want to make an implicit > binding for > an identifier, and for those cases you need to write an "unhygienic" > macro > which can be achieved with the more complex macro system "syntax- > case". > > Here's how your desired macro could be defined.  I will use > identifiers like > "" just for easier readability; they don't have any special > meaning: > >   (define-syntax def >     (lambda (stx) >       (syntax-case stx () >         ((_ ( ...) * ...) >          (let ((ret-id (datum->syntax stx 'return))) >            #`(define ( ...) >                (call/cc (lambda (#,ret-id) * ...)))))))) > > There's a few things here to take note of: > > - Unlike with syntax-rules, the syntax-case is contained in a lambda > which >   takes a single argument: a "syntax object" which is passed to > syntax-case > > - Unlike with syntax-rules, the "body" of the macro (where it begins > with a >   'let') is not immediately part of the generated code; that 'let' is > actually >   executed during compile-time.  The body of the macro must result in > an >   object of the type "syntax object" that represents the generated > code. > > - You see that I define a variable called "ret-id" which I bind to > the result >   of the expression: > >     (datum->syntax stx 'return) > >   which means "create a syntax object in the same lexical environment > as stx, >   and is represented by the symbol 'return'." > > - The actual code generation begins within the #`(...) which is a > shorthand >   for (quasisyntax (...)) just like '(...) is short for (quote > (...)).  The >   result of a quasisyntax expression is a syntax object.  Basically, > it's the >   most convenient way of creating a syntax object, but like syntax- > rules it's >   also hygienic by default and you need to insert "unhygienic" syntax > objects >   into it explicitly. > > - Within the quasisyntax, I use #,ret-id which is short for (unsyntax > ret-id) >   to inject the unhygienic syntax object that holds the symbol > 'return' into >   the generated code. > > For someone used to macros in the Common Lisp or Elisp style, this > may seem > over-complicated.  It's the cost of the "hygienic by default" > behavior. > > By the way I assume that you're just toying around with the language > to learn. > If you were thinking of using a 'def' macro like this in real code, I > would > discourage it because there's already a built-in mechanism that > allows the > programmer something very similar, called 'let/ec': > >   (import (ice-9 control)) > >   (define (test x) >     (let/ec return >       (cond >         ((= x 3) (return 7)) >         ((= x 2) (return 5))))) What does this return (defined with let/ec) do ? In the orevious versions I could see the call to call/cc so I could (somewhat) figure out the "jump" imlpied by calling return But in this last case, where is the return behaviour defined ?