From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Ian Price Newsgroups: gmane.lisp.guile.user Subject: Re: and-let* is not composable? Date: Sat, 02 Nov 2013 02:39:56 +0000 Message-ID: <87wqkrbk77.fsf@Kagami.home> References: <15322456.2mtMPoYDS9@warperdoze> <87hadtof0z.fsf@Kagami.home> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1383360015 8039 80.91.229.3 (2 Nov 2013 02:40:15 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 2 Nov 2013 02:40:15 +0000 (UTC) To: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Sat Nov 02 03:40:21 2013 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1VcR8P-0005Qi-8G for guile-user@m.gmane.org; Sat, 02 Nov 2013 03:40:21 +0100 Original-Received: from localhost ([::1]:40533 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VcR8O-0003Oo-8l for guile-user@m.gmane.org; Fri, 01 Nov 2013 22:40:20 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:39546) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VcR8C-0003N0-5d for guile-user@gnu.org; Fri, 01 Nov 2013 22:40:12 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VcR88-0001sx-0F for guile-user@gnu.org; Fri, 01 Nov 2013 22:40:08 -0400 Original-Received: from mail-wg0-x22d.google.com ([2a00:1450:400c:c00::22d]:63896) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VcR87-0001pI-Jo for guile-user@gnu.org; Fri, 01 Nov 2013 22:40:03 -0400 Original-Received: by mail-wg0-f45.google.com with SMTP id z12so237455wgg.0 for ; Fri, 01 Nov 2013 19:40:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:subject:references:mail-followup-to:date:in-reply-to :message-id:user-agent:mime-version:content-type; bh=PTCMJoTUzJFHA86xU4H3EK+/NPmRP+ueo+alvqGCvRw=; b=hatCDG4RE7Xf+8kQoXvug923DwfV8hosml+0O8jJWyNnJt+rLV2rAM0HeCuYTdp296 1uu5kU/IN35eHdl52Y+QXyVRSuEmjnohV7aNy47FUEsyiMtCq8T8epq9uHNkkR+FKlLh Hb+h/hYxlsJv4yU2ZDUaMzxVcSbU7NEnvkoB5XqbPZnkcc+8Q4b5LsQ3/myZ+62RvydG 3woD32yRiYp+vwNE/kRKbe+3uao9/+5SvxYkeAtuFBj0x60Xwcgd3h+hVJouCSnWrO6b qkGYdF///a1VblqXPCIWWIHET1ZKO7bns9kPhQa+7fePBRHpClq19swjgP4K40gp6btn choA== X-Received: by 10.180.219.33 with SMTP id pl1mr4383475wic.49.1383360002256; Fri, 01 Nov 2013 19:40:02 -0700 (PDT) Original-Received: from Kagami.home (host86-132-92-201.range86-132.btcentralplus.com. [86.132.92.201]) by mx.google.com with ESMTPSA id fu1sm12116916wib.8.2013.11.01.19.40.00 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 01 Nov 2013 19:40:00 -0700 (PDT) Mail-Followup-To: guile-user@gnu.org In-Reply-To: <87hadtof0z.fsf@Kagami.home> (Ian Price's message of "Mon, 09 Sep 2013 22:34:36 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c00::22d X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.14 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.org@gnu.org Original-Sender: guile-user-bounces+guile-user=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.user:10867 Archived-At: Ian Price writes: > The problem is one that occurs when hygienic and non-hygienic macros are > mixed. Here, and-let* is the non-hygienic one. Basically, in a hygienic > macro, you carry around a bunch of context to allow you to refer to the > right variable names. Then defmacro comes along, strips all that away, > and uses the raw symbol names. > > We can fix and-let* to be hygienic, that's pretty easy, but I'm not sure > what you can do about this in general. It's not like you can pass in the > gensymed name, because that will break the way people who for some > reason still right defmacros expect them to work. > > Dunno, maybe I'm just missing some insight here. This discussion came up on #scheme yesterday, and Eli Barzilay mentioned that Racket tries to be more clever with its legacy defmacro by keeping a hash associating input sexps with their syntax objects. This is in no way a silver bullet, but for many macros, this is liable to work out really nicely. An example implementation is below, though I have a few notes indicating things needing fixed. (define-syntax define-macro (lambda (x) "Define a defmacro." (syntax-case x () ((_ (macro . args) doc body1 body ...) (string? (syntax->datum #'doc)) #'(define-macro macro doc (lambda args body1 body ...))) ((_ (macro . args) body ...) #'(define-macro macro #f (lambda args body ...))) ((_ macro transformer) #'(define-macro macro #f transformer)) ((_ macro doc transformer) (or (string? (syntax->datum #'doc)) (not (syntax->datum #'doc))) #'(define-syntax macro (lambda (y) (define (recontextualize form context default) (define (walk x) ;; is there any possibility of a circular syntax object? (cond ((hashv-ref context x) => (lambda (x) x)) ((pair? x) (cons (walk (car x)) (walk (cdr x)))) ((vector? x) (vector-map walk x)) ((symbol? x) (datum->syntax default x)) (else x))) (walk form)) (define (build-context form stx-form) (define ctx (make-hash-table)) (define (walk x y) (hashv-set! ctx x y) ;; is there any possibility of a circular syntax object? (cond ((pair? x) (walk (car x) (car (syntax-e y))) (walk (cdr x) (cdr (syntax-e y)))) ((vector? x) (vector-for-each2 walk x (syntax-e y))) ;; Any other types needing handled? )) (walk form stx-form) ctx) (define (vector-for-each2 f v1 v2) (define len (vector-length v1)) (define v* (make-vector len)) (let loop ((i 0)) (unless (= i len) (vector-set! v* i (f (vector-ref v1 i) (vector-ref v2 i))) (loop (+ i 1)))) v*) (define (vector-map f v) (define len (vector-length v)) (define v* (make-vector len)) (let loop ((i 0)) (unless (= i len) (vector-set! v* i (f (vector-ref v i))) (loop (+ i 1)))) v*) (define (syntax-e obj) (syntax-case obj () [(first . rest) (cons #'first #'rest)] [#(value (... ...)) (apply vector #'(value (... ...)))] [a (syntax->datum #'a)])) doc ;; FIXME: may not be a docstring, and so would fail above #((macro-type . defmacro) (defmacro-args args)) (syntax-case y () ((_ . args) (let* ((v (syntax->datum #'args)) (ctx (build-context v #'args))) (recontextualize (apply transformer v) ctx y)))))))))) This version of define-macro still fails on the original macros as posted by Panicz Maciej Godek, but gives the "right" result using stis's ck macro version. At 2:30am, I'm not liable to get to the bottom of why till tomorrow, but I think doing something like this is a positive step. -- Ian Price -- shift-reset.com "Programming is like pinball. The reward for doing it well is the opportunity to do it again" - from "The Wizardy Compiled"