From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Damien Mattei Newsgroups: gmane.lisp.guile.user Subject: Re: return macro Date: Mon, 28 Jun 2021 10:53:53 +0200 Message-ID: References: <1142492b-16bf-7181-8d93-38bfc2d3c748@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="23851"; mail-complaints-to="usenet@ciao.gmane.io" Cc: guile-user To: Taylan Kammer Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Mon Jun 28 10:54:23 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 1lxn25-0005xB-5Z for guile-user@m.gmane-mx.org; Mon, 28 Jun 2021 10:54:21 +0200 Original-Received: from localhost ([::1]:35018 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxn23-00049w-KU for guile-user@m.gmane-mx.org; Mon, 28 Jun 2021 04:54:19 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:39072) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxn1s-00049m-Qb for guile-user@gnu.org; Mon, 28 Jun 2021 04:54:08 -0400 Original-Received: from mail-il1-x12f.google.com ([2607:f8b0:4864:20::12f]:39929) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lxn1q-0005De-5K for guile-user@gnu.org; Mon, 28 Jun 2021 04:54:08 -0400 Original-Received: by mail-il1-x12f.google.com with SMTP id o10so11917165ils.6 for ; Mon, 28 Jun 2021 01:54:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=9qFX7y5q43FIOcArjzcCynV0N0hMo05kpF3HHNpavEk=; b=Q59M3US3vWzIvATLHyPk9VED8xAvth9ySx/Fxyp8x338jf2maXCf/YIR1fR7RIpyKX 4B2rcmGVPtqK87ZTgq8IJCBtXqUfGUU5y+C3P3uY4PFl+nopt7ebVTPIYOWmMmmtyK3G r0BbOnBzty9p2kBUmjmC+1gU/1VRv30/Vva8MxIsifllyezZ7kjfpkN2GBVnPq1d5tmn 9vXc5wTRG2BdbxAo4aWdRFCFkd+c8JDRW3l1cLTy7GFRednzKef4ihpnWJ+OjqxEmn0j 5jPCqyIYy4gaPIdtdSsfbO8oAvl28s3oBdvnpCaD9JzypKv0Pe5ajKzIurXcCtS6xhmW y4OA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=9qFX7y5q43FIOcArjzcCynV0N0hMo05kpF3HHNpavEk=; b=g4D1nTU4MTDea4qv7nWKBCEzI8rHNn0R9hnaGbBzu1H9b4pKf1l1qPzZN3z+DzB1/d DmX4nMBjAbGSa8WIIhEWFWv/y23l/uQYZyBfXHIkAozRAKPA4ckzfL30oQL5obq9N/K/ ipiu289RcutmIHef1pEmQCEJK/GNIPd9uTeryp5C4/TQ4d0zG2+39Px3hKwQPFtyxjis 7we93uNbI7b9VGVtLR/Kn9CBoBCLH9VwdV7eLhUNo4GTnq7REhsrBnvWLkdZDb7kiobe IdQRRcs5yquFPC7kHw3RmzXGBmfDfNcpmDNJKNSE1BWgV7c3AgEoBdj1a9QHiUgOWVOs mNSg== X-Gm-Message-State: AOAM530+T/eLLDv+67+BIDm0cozEzj4V5U+IDu6CAPEuJ4+I+oBBk9mc iVVsbHkTSQdefjxXNqwBWMsbZe4K0SRLBA2nb1M= X-Google-Smtp-Source: ABdhPJwsJN8Rywt2/19Qf9J0zTaw1ERXxFdkmg/zqsefW7wh/OITUh8rS3tewcDcapNtLMTQfU/LKlllVQjACoGmz5o= X-Received: by 2002:a92:d483:: with SMTP id p3mr5717348ilg.113.1624870444985; Mon, 28 Jun 2021 01:54:04 -0700 (PDT) In-Reply-To: <1142492b-16bf-7181-8d93-38bfc2d3c748@gmail.com> Received-SPF: pass client-ip=2607:f8b0:4864:20::12f; envelope-from=damien.mattei@gmail.com; helo=mail-il1-x12f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 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, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Content-Filtered-By: Mailman/MimeDel 2.1.23 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:17622 Archived-At: thank Taylan i already use all that in the past ( https://github.com/damien-mattei/library-FunctProg/blob/master/syntactic-sugar.scm#L133 ) but it was late ,past 1h00 and i forget it, and it was not compatible with R5RS thank for your long and clear explainations... i did not use let/ec because the problem was not with let/ec or call/cc but with the macro hygiene and i wanted to stay compatible with other scheme,let/ec should be guile only and i suppose let/ec made with call/cc . regards, damien On Mon, Jun 28, 2021 at 3:15 AM Taylan Kammer wrote: > 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))))) > > As you see it allows you to define a "return" keyword anywhere, and it > doesn't need to be part of a function definition, it can appear anywhere. > > -- > Taylan >