From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Panicz Maciej Godek Newsgroups: gmane.lisp.guile.user Subject: Re: and-let* is not composable? Date: Fri, 13 Sep 2013 20:40:19 +0200 Message-ID: References: <87li34mue7.fsf@Kagami.home> <8761u7o3n3.fsf@Kagami.home> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=20cf30781092c03e6604e6482fbe X-Trace: ger.gmane.org 1379097640 6388 80.91.229.3 (13 Sep 2013 18:40:40 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 13 Sep 2013 18:40:40 +0000 (UTC) To: "guile-user@gnu.org" , Ian Price Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Fri Sep 13 20:40:40 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 1VKYIK-0005Jp-Lp for guile-user@m.gmane.org; Fri, 13 Sep 2013 20:40:40 +0200 Original-Received: from localhost ([::1]:50718 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VKYIK-0004Th-8S for guile-user@m.gmane.org; Fri, 13 Sep 2013 14:40:40 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:45144) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VKYI2-0004QX-Rc for guile-user@gnu.org; Fri, 13 Sep 2013 14:40:24 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VKYI1-0003mg-6T for guile-user@gnu.org; Fri, 13 Sep 2013 14:40:22 -0400 Original-Received: from mail-vb0-x229.google.com ([2607:f8b0:400c:c02::229]:38256) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VKYI1-0003mZ-0I for guile-user@gnu.org; Fri, 13 Sep 2013 14:40:21 -0400 Original-Received: by mail-vb0-f41.google.com with SMTP id g17so1271062vbg.28 for ; Fri, 13 Sep 2013 11:40:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=3kkXTY4e7LFUvoi2a6UMsJOw96DN1Xs61xyJdkd0RQI=; b=eJG5zxgYac1RyNaEm2thLodmZr6tUrTJ08Fzc9/IzJhvHS/YL9PoFNFm/rXWP/Rl9t M0L0AppklAh2t93v4nlyFs4/L5HGBhjkhUoguO9WxYhRHQ0PICAccANIf0yOJjeCiWWL cHq1wOgA99vrwt814WK637zO9GOWSQody29hgZ1eR3MxzV9DJNJeFlBMnIWo8aQjxwtM MzrfF0Sg1Z2OP6qFpHLrfzJEYeyFYQZltMyTZz56yPO+gJFhotF1gFC724ywRh8E/wv2 q9QR7KcmWQptmpMY36GYJoKzBagK+ZZVFHzKh8wQYReIbHbsmnNLvvPKXJeRAKzWEzMP 2fXw== X-Received: by 10.52.24.4 with SMTP id q4mr1747287vdf.34.1379097620000; Fri, 13 Sep 2013 11:40:20 -0700 (PDT) Original-Received: by 10.221.45.135 with HTTP; Fri, 13 Sep 2013 11:40:19 -0700 (PDT) In-Reply-To: <8761u7o3n3.fsf@Kagami.home> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400c:c02::229 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:10799 Archived-At: --20cf30781092c03e6604e6482fbe Content-Type: text/plain; charset=ISO-8859-1 > Well, while syntax-rules macros are quite easy to understand > > (at least from the user's point of view), although sometimes a little > > tricky, the syntax-case system I find still too difficult to use. > > define-macro, on the other hand, is very easy to explain > > even to beginner programmers, although the resulting macros > > are much more difficult to analyse. > If you, or the other people who are confused by syntax-case, can point > to the parts of the manual that confuse you, so we can clear them up, I > think we'd all appreciate it. > > The order of presentation in the manual is that syntax-rules macros are explained first, because they are more limited, and there's no need to get into details regarding syntax objects. I used to explain the "syntax-rules" macros to my friends by first showing "what we want to transform into what", and then packing it up in some magic to work (because basically that's how I understand them). The advantage was that the meaning of the macro is readily visible and there's no need to analyse the code. The manual however makes very little reference to define-macro system to explain how syntax-case works. It is easy to see that lisp programs are lists of symbols, and so they can be processed like any other lists of symbols before they are evaluated -- that's the essentials of lisp macros. In case of "syntax-case" some new mysterious notions appear: namely, the unfamous syntax objects. And while it is easy to imagine how the list of symbols look like, all we read about in the manual is that "the syntax expander represents identifiers as annotated syntax objects, attaching such information to those syntax objects as is needed to maintain referential transparency". We don't know what sort of information is that, and why is it better to use syntax-case over define-macro. Especially if we compare the "anamorphic if" definition from the manual, (define-syntax aif (lambda (x) (syntax-case x () ((_ test then else) (syntax-case (datum->syntax x 'it) () (it #'(let ((it test)) (if it then else)))))))) with the most straightforward "anamorphic if" with define-macro: (define-macro (aif test then else) `(let ((it ,test)) (if it ,then ,else))) (Even if the latter is not exactly right, as is argued in section 6.10.5, it generally does its job) Also, I have to admit that I still don't understand what the syntax-case macro above is doing. Furthermore, it isn't clear why syntax->datum takes only one argument, and datum->syntax takes two (a syntax object and the "datum" itself) > Fundamentally, syntax-case shouldn't be harder to use than define-macro > 99% of the time, if you remember > > - macros are functions from "syntax-objects" to syntax-objects > - syntax-objects are smart symbols > - syntax->datum to remove the smartness > - datum->syntax is for when you want to break hygiene (but syntax > parameters are better where applicable) > - use quasisyntax to construct lists of syntax-objects instead of > quasiquote to construct lists of symbols. > Maybe showing a sufficient number of examples would be more helpful, because I haven't got a clue "where syntax parameters are applicable" or how I could use quasisyntax and unsyntax. By the way, I've had another problem when defining a macro. I've been trying to implement something like dynamical scoping, but such that it wouldn't require introducing global variables The idea is that one can write (with-default ((a 5)) (define (f x) (+ x (specific a)))) and that later the procedure could be used like that: (f 10) ===> 15 (specify ((a 20)) (f 10)) ===> 30 The first attempt was that there could be a global hash table *specifics* that would store the lists of values, and that "specific" could be a local macro that would expand to a hash reference. So I tried to implement that using syntax-rules in the following way: (define-syntax with-default (syntax-rules () ((_ ((name value) ...) actions ...) (let-syntax ((specific (syntax-rules (name ...) ((_ name) (hash-ref *specifics* 'name value)) ;; don't mind shadowing for now ...))) actions ...)))) However, when I tried to use it, it seemed that the let-syntax behaves as if it wasn't there (so it didn't behave at all!): (with-default ((a 5)) (define (f x)(+ x (specific a)))) The situation was (again) resolved by creating a nasty combination of "define-macro" and "syntax-rules", namely: (define-macro (with-default bindings . actions) (match bindings (((names values) ...) `(let-syntax ((specific (syntax-rules ,names ,@(map (match-lambda ((name value) `((_ ,name) (hash-ref *defaults* ',name ,value)))) bindings)))) ,@actions)))) It's not that I like it. I really don't. But I don't know how how else this could be achieved, nor why the former solution so stubbornly resists to work. Thanks, M. --20cf30781092c03e6604e6482fbe Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
> Well, while syntax= -rules macros are quite easy to understand
> (at least from the user's point of view), although sometimes a lit= tle
> tricky, the syntax-case system I find still too difficult to use.
> define-macro, on the other hand, is very easy to explain
> even to beginner programmers, although the resulting macros
> are much more difficult to analyse.
If you, or the other people who are confused by syntax-case, can poin= t
to the parts of the manual that confuse you, so we can clear them up, I
think we'd all appreciate it.


The order of presentation in the = manual is that syntax-rules macros=A0
are explained first, becaus= e they are more limited, and there's no=A0
need to get into d= etails regarding syntax objects.

I used to explain the "syntax-rules" macros t= o my friends by
first showing "what we want to transform int= o what", and then packing
it up in some magic to work (becau= se basically that's how I
understand them). The advantage was that the meaning of the macro
is readily visible and there's no need to analyse the code.
=

The manual however makes very little reference to defin= e-macro system=A0
to explain how syntax-case works. It is easy to see that lisp programs=
are lists of symbols, and so they can be processed like any othe= r
lists of symbols before they are evaluated -- that's the es= sentials
of lisp macros. In case of "syntax-case" some new mysterious=
notions appear: namely, the unfamous syntax objects. And while i= t
is easy to imagine how the list of symbols look like, all we re= ad
about in the manual is that "the syntax expander represents=A0
identifiers as annotated syntax objects, attaching such information= =A0
to those syntax objects as is needed to maintain referential= =A0
transparency". We don't know what sort of information is that= , and
why is it better to use syntax-case over define-macro.

Especially if we compare the "anamorphic if"= definition from the
manual,
(define-syntax aif
=A0 =A0 =A0 =A0(lambda = (x)
=A0 =A0 =A0 =A0 =A0(syntax-case x ()
=A0 =A0 =A0 = =A0 =A0 =A0((_ test then else)
=A0 =A0 =A0 =A0 =A0 =A0 (syntax-ca= se (datum->syntax x 'it) ()
=A0 =A0 =A0 =A0 =A0 =A0 =A0 (it
=A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 #'(let ((it test))
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (if it then else))))))))

with the most straigh= tforward "anamorphic if" with define-macro:

(define-macro (aif test then else)
=A0 `(let = ((it ,test))
=A0 =A0 =A0(if it
=A0 =A0 =A0 =A0 =A0,then=
=A0 =A0 =A0 =A0 =A0,else)))

(Even if th= e latter is not exactly right, as is argued in section
6.10.5, it generally does its job)

Also, I ha= ve to admit that I still don't understand what the
syntax-cas= e macro above is doing. Furthermore, it isn't clear why=A0
syntax->datum takes only one argument, and datum->syntax takes
<= div>two (a syntax object and the "datum" itself)

=A0
Fundamentally, syntax-case shouldn't be harder to use than define-macro=
99% of the time, if you remember

- macros are functions from "syntax-objects" to syntax-objects - syntax-objects are smart symbols
- syntax->datum to remove the smartness
- datum->syntax is for when you want to break hygiene (but syntax
=A0 parameters are better where applicable)
- use quasisyntax to construct lists of syntax-objects instead of
=A0 quasiquote to construct lists of symbols.


Maybe showing a sufficient number= of examples would be
more helpful, because= I haven't got a clue "where syntax
parameters are applicable" or how I could u= se quasisyntax
and unsyntax.

By the way, I&#= 39;ve had another problem when defining a macro.
I've been trying to implement something like dynamical scoping,
but such that it wouldn't require introducing global variables<= /div>

The idea is that one can write

(with-default ((a 5))
(define (f x) (+ x (specific a))))

an= d that later the procedure could be used like that:
(f 10)
<= div> =3D=3D=3D> 15
(specify ((a 20))
(f 10))
=3D=3D=3D> 30

The first attempt was that there could be a global hash tab= le
*specifics* that would store the lists of values, and that=A0
&qu= ot;specific" could be a local macro that would expand to a hash
<= div>reference. So I tried to implement that using syntax-rules
in the following way:

(define-syntax with-default<= /div>
=A0 (syntax-rules ()
=A0 =A0 ((_ ((name value) ...)
=A0 =A0 =A0 =A0 actions ...)
=A0 =A0 =A0(let-syntax ((spec= ific (syntax-rules (name ...)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ((_ name)<= /div>
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(h= ash-ref *specifics* 'name value))
=A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; don't mind shadowing for now
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ...)))
=A0 =A0 =A0 =A0actions ...))))

However, when = I tried to use it, it seemed that the let-syntax
behaves as if it= wasn't there (so it didn't behave at all!):

(with-default ((a 5))
=A0 (define (f x)(+ x (specific a))))

The sit= uation was (again) resolved by creating a nasty combination
of &q= uot;define-macro" and "syntax-rules", namely:

(define-macro (with-default bindings . actions)
=A0 (m= atch bindings
=A0 =A0 (((names values) ...)
=A0 =A0 =A0= `(let-syntax ((specific (syntax-rules ,names
=A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0,@(map (match-lambda
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 ((name value)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0`((_ ,name)
= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0(hash-ref *defaults*
=A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0',name ,value))))
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 bindings))))
=A0 =A0 =A0 =A0 ,@actions))))

=
It's not that I like it. I really don't. But I don't= know how how
else this could be achieved, nor why the former sol= ution
so stubbornly resists to work.

Thanks,
<= div>M.

--20cf30781092c03e6604e6482fbe--