From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Taylan Kammer Newsgroups: gmane.lisp.guile.user Subject: Re: Syntax-Case macro that selects the N-th element from a list Date: Mon, 5 Apr 2021 17:08:29 +0200 Message-ID: <7a5af132-13a2-65eb-5a36-f1e4e6c840ba@gmail.com> References: <87im5155pu.fsf@web.de> 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="13296"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.9.0 To: "Dr. Arne Babenhauserheide" , Guile User Mailing List Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Mon Apr 05 17:19:08 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 1lTR0N-0003Kw-Fy for guile-user@m.gmane-mx.org; Mon, 05 Apr 2021 17:19:07 +0200 Original-Received: from localhost ([::1]:39438 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lTR0M-0000Wk-H0 for guile-user@m.gmane-mx.org; Mon, 05 Apr 2021 11:19:06 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:52204) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lTQqC-0000Pe-Ir for guile-user@gnu.org; Mon, 05 Apr 2021 11:08:36 -0400 Original-Received: from mail-ed1-x52d.google.com ([2a00:1450:4864:20::52d]:36776) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lTQq8-00056h-Rw for guile-user@gnu.org; Mon, 05 Apr 2021 11:08:36 -0400 Original-Received: by mail-ed1-x52d.google.com with SMTP id o19so12916399edc.3 for ; Mon, 05 Apr 2021 08:08:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-language:content-transfer-encoding; bh=7jlizpQDnWM/1sp4h4jc0MdM9YzTIro87i4Lms8Ayo0=; b=XjeUmeEjjUk47poVyE694U3cLyB244Ex7fyfcE7ri8Aw55SAJx9Ci+dEM9nMin5Sag gafmjntBlSOQtpO2b8zKSfuUD36xQmst7xWDyIYAHToOeCdfkysPnZ6l0SNIW+62EhEK nB1TifvB+hJWhCfgc+l8DS5+SSQScXq04YIUjiOCjfDnDHHzSgT6iyTcdPdn2+BFLTP2 7cd9SGQ3Xomn/xVbDhkEoNtpMBbP1SuBpK/OKalJw7t1AMRd/O5+kamTCTE83t9P1SpG a0kojS084fo/e/UTTd/LxCRbBSPpyGINU60JRAOrD+tIneUqUPbxbrA5r3HiU/qrJSm4 WNVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=7jlizpQDnWM/1sp4h4jc0MdM9YzTIro87i4Lms8Ayo0=; b=r9kuOiYam2bvx1oHnp0PojRbfKfUHIniKf8RY8CtOjM+MIJWrQvcq8v214OzoIkM/5 4zPMWzjwVtOGJs9/e9psgyxLG0Ha22DzXhFzXdRKrAW6vJobZMP6WDHCGhKn6eaErj0A V4J3WjFl50G6JQrfUeb0shgKuA77y3moX3BGx7840pwnyXDQNWjzNhmxk4vjWYwUtQmx YNHkRjqZND7CSUa0s4/PPZG1F7flcHxqXArKwefmO/PX9Bz8uW6kj7E6jtqtJSNxbO3E KPccWfdm9kZDLE6aWEvNYc1YbjxFkWss3SYnKa6kaANWQLT5WpStT+dVEJOSGGXk/LLF FHjQ== X-Gm-Message-State: AOAM531FI6gUrfR3BnqCvpiFYge7aRL6uyFvD1dCSjyDeuN11BEIoSkf Lx2NplTVBT9QhJw7v4aJL9ZoIsEjIqU= X-Google-Smtp-Source: ABdhPJwgM7j80lBh+GmiunByoD+Wy3W6p2qXtnQNgY8GsImPuF4Bwld8n5gmtCuEtUG3FaIWdJXPxQ== X-Received: by 2002:a05:6402:3da:: with SMTP id t26mr6476822edw.84.1617635310293; Mon, 05 Apr 2021 08:08:30 -0700 (PDT) Original-Received: from [192.168.178.20] ([109.90.125.150]) by smtp.gmail.com with ESMTPSA id q2sm9037215eje.24.2021.04.05.08.08.29 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 05 Apr 2021 08:08:29 -0700 (PDT) In-Reply-To: <87im5155pu.fsf@web.de> Content-Language: en-US Received-SPF: pass client-ip=2a00:1450:4864:20::52d; envelope-from=taylan.kammer@gmail.com; helo=mail-ed1-x52d.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, NICE_REPLY_A=-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-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:17395 Archived-At: On 05.04.2021 13:30, Dr. Arne Babenhauserheide wrote: > Hi, > > In dryads-wake I need selection of the element in a list in a macro from > user-input. Currently I have multiple macros, and the correct one (which > strips the non-selected choices) is selected in a simple cond: > > (define-syntax-rule (Choose resp . choices) > "Ask questions, apply consequences" > (cond > ((equal? resp 1) ;; resp is user-input. It is a natural number. > (Respond1 choices)) > ((equal? resp 2) > (Respond2 choices)) > ((equal? resp 3) > (Respond3 choices)) > (else > #f))) > > For this however I have three syntax-case macros: > > (define-syntax Respond1 > (lambda (x) > (syntax-case x () > ((_ ((question consequences ...) choices ...)) > #`(begin > (respond consequences ...))) > ((_ (choices ...)) > #`(begin #f))))) > > (define-syntax Respond2 > (lambda (x) > (syntax-case x () > ((_ (choice choices ...)) > #`(begin > (Respond1 (choices ...)))) > ((_ (choices ...)) > #`(begin #f))))) > > (define-syntax Respond3 > (lambda (x) > (syntax-case x () > ((_ (a b choices ...)) > #`(Respond1 (choices ...))) > ((_ (choices ...)) > #`(begin #f))))) > > > I would like to get rid of those three definitions and replace them by > at most two (one that strips N initial list entries, and Respond1). > > I cannot move to procedures, because I have code that must be executed > only during final processing, and when I evaluate any of the > consequences (as it happens with procedure-arguments), then the timing > of the code execution does not match anymore. So I must absolutely do > this in macros. > > > I’ve tried to get that working, but all my tries failed. Is there a way > and can you show it to me? > > This is a minimal working example. The output should stay the same, > except for part 4, which needs this change to work (see at the bottom), > but I would like to: > > - replace Respond2 and Respond3 by something recursive, so resp can have > arbitrary high values (not infinite: max the length of the options) and > - replace the cond-clause by a call to the recursive macro. > > (define-syntax-rule (respond consequence consequence2 ...) > (begin > (write consequence) > (when (not (null? '(consequence2 ...))) > (write (car (cdr (car `(consequence2 ...)))))))) > > (define-syntax Respond1 > (lambda (x) > (syntax-case x () > ((_ ((question consequences ...) choices ...)) > #`(begin > (respond consequences ...))) > ((_ (choices ...)) > #`(begin #f))))) > > (define-syntax Respond2 > (lambda (x) > (syntax-case x () > ((_ (choice choices ...)) > #`(begin > (Respond1 (choices ...)))) > ((_ (choices ...)) > #`(begin #f))))) > > (define-syntax Respond3 > (lambda (x) > (syntax-case x () > ((_ (a b choices ...)) > #`(Respond1 (choices ...))) > ((_ (choices ...)) > #`(begin #f))))) > > > (define-syntax-rule (Choose resp . choices) > "Ask questions, apply consequences" > (cond > ((equal? resp 1) > (Respond1 choices)) > ((equal? resp 2) > (Respond2 choices)) > ((equal? resp 3) > (Respond3 choices)) > (else > #f))) > > > (display "Choose 1: should be bar:") > (Choose 1 (foo 'bar) (foo 'war 'har) (foo 'mar) (foo 'tar)) > (newline) > (display "Choose 2: should be warhar:") > (Choose 2 (foo 'bar) (foo 'war 'har) (foo 'mar) (foo 'tar)) > (newline) > (display "Choose 3: should be mar:") > (Choose 3 (foo 'bar) (foo 'war 'har) (foo 'mar) (foo 'tar)) > (newline) > (display "Choose 4: should be tar:") > (Choose 4 (foo 'bar) (foo 'war 'har) (foo 'mar) (foo 'tar)) > (newline) > (display "Choose 5: should be #f:") > (Choose 5 (foo 'bar) (foo 'war 'har) (foo 'mar) (foo 'tar)) > (newline) > > > Best wishes, > Arne > Is there a reason you want to separate 'choose' from the various 'respondN' macros? That seems superfluous to me. And if the number of choices is limited, you don't even need to use procedural macros. The following works: ;; Note: I like using the notation for template variables. ;; Feels highly intuitive to me. (define-syntax choose (syntax-rules () ((_ 1 ...) (respond )) ((_ 2 ...) (respond )) ((_ 3 ...) (respond )) ((_ 4 ...) (respond )) ((_ 5 ...) (respond )) ((_ ...) #f))) You could also leave out the final clause and thus let it be an implicit syntax error, or explicitly invoke 'syntax-error' with an explanation. But if you want to support an arbitrary numbers of choices, the following procedural macro will do it: (define-syntax choose (lambda (stx) (syntax-case stx () ((_ . ) (let* ((n (syntax->datum #')) (choice-list (syntax->datum #')) (choice-datum (list-ref choice-list (- n 1))) (choice-stx (datum->syntax #' choice-datum))) #`(respond #,choice-stx)))))) I've written a very trivial explanation of syntax-case usage here, in case anyone struggles as I did at first: http://taylanub.github.io/doc/syntax-case-example.scm.txt Hope that helps! - Taylan