unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Re: and-let* is not composable?
       [not found] <CAMFYt2Z2qxkdrf1WOGZ4FowoAxLY8vtLUB-nAprg_fi2_sbCew@mail.gmail.com>
@ 2013-09-09 20:26 ` Stefan Israelsson Tampe
  2013-09-09 21:34   ` Ian Price
  0 siblings, 1 reply; 4+ messages in thread
From: Stefan Israelsson Tampe @ 2013-09-09 20:26 UTC (permalink / raw)
  To: guile-user, guile-devel

First of all define-macro is asking for trouble. don't use it is the
general recomendation for guile.

If you look into the kanren soures you will find,

(define-syntax lambda@
  (syntax-rules ()
    ((_ (formal) body0 body1 ...) (lambda (formal) body0 body1 ...))
    ((_ (formal0 formal1 formal2 ...) body0 body1 ...)
     (lambda (formal0)
       (lambda@ (formal1 formal2 ...) body0 body1 ...)))))

(define-syntax @  
  (syntax-rules ()
    ((_ rator rand) (rator rand))
    ((_ rator rand0 rand1 rand2 ...) (@ (rator rand0) rand1 rand2 
...))))

That is currying where lambda@ is your define-curried and @ is the
application of curried functions in a convinient way e.g.

(test-check 'test-@-lambda@
  (@ (lambda@ (x y z) (+ x (+ y z))) 1 2 3)
  6)

It's not what you wnt but this gives you a good pattern to maybe base
your work on. If you still wan't to design defined curried ontop of 
syntax-rules I would recoment to use the ck macro e.g.

(define-syntax ck
  (syntax-rules (quote)
    ((ck () 'v) v)                      ; yield the value on empty stack

    ((ck (((op ...) ea ...) . s) 'v)    ; re-focus on the other 
argument, ea
     (ck-arg s (op ... 'v) ea ...))

    ((ck s (op ea ...))                 ; Focus: handling an 
application;
     (ck-arg s (op) ea ...))))          ; check if args are values

(define-syntax ck-arg
  (syntax-rules (quote)
    ((ck-arg s (op va ...))             ; all arguments are evaluated,
     (op s va ...))                     ; do the redex

    ((ck-arg s (op ...) 'v ea1 ...)     ; optimization when the first ea
     (ck-arg s (op ... 'v) ea1 ...))    ; was already a value

    ((ck-arg s (op ...) ea ea1 ...)     ; focus on ea, to evaluate it
     (ck (((op ...) ea1 ...) . s) ea))))


1) define a partitioner, (a b c) -> (() a) ((a) b) ((a b) c)) with
(define-syntax ck-partition 
  (syntax-rules (quote)
    ((_ s '(a ... b) 'l)    
     (ck-partition s '(a ...) '(((a ...) b) . l)))
    ((_ s '() 'l)
     (ck s 'l))))

2) compile the pieces together
(define-syntax compile-curried
  (syntax-rules (quote)
    ((_ s 'name '(a ...) 'body '(((b ...) c) ...))
      (ck ()
      '(define-syntax name
         (syntax-rules ()
           ((_ a ...) (begin . body))
	   ((_ b ...) (lambda (c) (name b ... c)))
	   ...))))))

3) The overall macro
(define-syntax-rule (define-curried (name a ...) . body)
  (ck () (compile-curried 'name '(a ...) 'body 
  (ck-partition '(a ...) '()))))

Now we need the definition of the ck macro,
  
  http://okmij.org/ftp/Scheme/macros.html

We have it in guile also in master. So lets try it, ...

scheme@(guile-user)>  (define-curried (f a b c d) (list a b c d))
scheme@(guile-user)> (((f 1 2) 3) 4)
$5 = (1 2 3 4)

it works, lets try out the problematic vode you have,

(use-modules (srfi srfi-2))
(use-modules (srfi srfi-1))

(define-curried (string-matches pattern string)
   (and-let* ((match-struct (string-match pattern string))
                 (count (match:count match-struct)))
      (map (lambda(n)(match:substring match-struct n))
         (iota (1- count) 1))))

scheme@(guile-user)> (string-matches "([a-z])" "a")
$4 = ("a")


,exp ((string-matches "([a-z])") "a")
$5 = ((lambda (string-871)
   (let ((match-struct-876
           (string-match "([a-z])" string)))
     (if match-struct-876
       (let ((count-880 (match:count match-struct-876)))
         (if count-880
           (map (lambda (n-883)
                  (match:substring match-struct-876 n-883))
                (iota (#{1-}# count-880) 1))
           #f))
       #f)))
 "a")

And we see that string is not managed correctly. Is this a bug? I
can't understand why this is not treated as intended!



> On Monday, September 09, 2013 07:35:16 PM Panicz Maciej Godek wrote:
> Hi,
> some time ago I posted to comp.lang.scheme with the
> following proposal of "define-curried" macro:
> 
> (define-macro (define-curried signature . body)
>   (match signature
>     ((name args ...)
>      `(define-syntax ,name
>         (syntax-rules ()
>           ((_ ,@args)
>            (begin ,@body))
>           ,@(let loop ((args* args))
>               (match args*
>                 (() '())
>                 ((first ... last)
>                  (cons `((_ ,@first #;...)
>                          (lambda(,last)(,name ,@args*)))
>                        (loop first #;...))))))))))
> 
> The idea was to expand, e.g. (define-curried (f a b c d) (list a b c
> d)) to:
> 
> (define-syntax f
>   (syntax-rules ()
>     ((_ a b c d)
>      (begin (list a b c d)))
>     ((_ a b c)
>      (lambda(d)
>        (f a b c d)))
>     ((_ a b)
>      (lambda(c)
>        (f a b c)))
>     ((_ a)
>      (lambda(b)
>        (f a b)))
>     ((_)
>      (lambda(a)
>        (f a)))))
> 
> I asked whether it would be possible to write that code using
> syntax-rules only, but I received no answer, not even a reprimend. I
> used that code to implement a quite convinient macro (actually that
> urge was my inspiration):
> 
> (define-curried (matches? pattern x)
>   (match x
>     (pattern #t)
>     (else #f)))
> 
> so that I could write
> 
> (filter (matches? (two elements)) some-list)
> 
> Recently, I tried to write a nicer interface to string-match, that
> would allow me to extract parenthesized subexpressions easily. My
> first guess was this:
> 
> (define-curried (string-matches pattern string)
>   ;;CAUTION: buggy version
>   (and-let* ((match-struct (string-match pattern string))
>                 (count (match:count match-struct)))
>      (map (lambda(n)(match:substring match-struct n))
>         (iota (1- count) 1))))
> 
> and although it worked with a complete list of arguments,
> (string-matches "([a-z])" "a")
> ==> ("a")
> it failed to curry properly
> ((string-matches "([a-z])") "a")
> ==> some strange error
> 
> It turned out, that the "string" symbol doesn't get tied
> with the lambda argument:
> 
> (expand (string-matches "([a-z])"))
> ==>
> (lambda (string-12552)
>   (let ((match-struct-12557 (string-match "([a-z])" string)))
> ;; the reason of our tears and despair is right here^^^
>     (if match-struct-12557
>         (let ((count-12561 (match:count match-struct-12557)))
>           (if count-12561
>               (map (lambda (n-12564)
>                      (match:substring match-struct-12557 n-12564))
>                    (iota (#{1-}# count-12561) 1))
>               #f))
>         #f)))
> 
> This forced me to write another definition of string-matches
> that doesn't use the and-let* macro and works as expected:
> 
> (define-curried (string-matches pattern s)
>   (let ((match-struct (string-match pattern s)))
>     (if match-struct
> (let ((count (match:count match-struct)))
>           (map (lambda(n)(match:substring match-struct n))
>                (iota (1- count) 1)))
>         #f)))
> 
> Nevertheless I am a little worried that either my macro,
> or and-let* is not composable. Perhaps there's some wise
> man here who knows what's going on.
> 
> Best regards,
> M.




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: and-let* is not composable?
  2013-09-09 20:26 ` and-let* is not composable? Stefan Israelsson Tampe
@ 2013-09-09 21:34   ` Ian Price
  2013-09-10 13:42     ` Stefan Israelsson Tampe
  0 siblings, 1 reply; 4+ messages in thread
From: Ian Price @ 2013-09-09 21:34 UTC (permalink / raw)
  To: Stefan Israelsson Tampe; +Cc: guile-user, guile-devel

Stefan Israelsson Tampe <stefan.itampe@gmail.com> writes:

> (use-modules (srfi srfi-2))
> (use-modules (srfi srfi-1))
>
> (define-curried (string-matches pattern string)
>    (and-let* ((match-struct (string-match pattern string))
>                  (count (match:count match-struct)))
>       (map (lambda(n)(match:substring match-struct n))
>          (iota (1- count) 1))))
>
> scheme@(guile-user)> (string-matches "([a-z])" "a")
> $4 = ("a")
>
>
> ,exp ((string-matches "([a-z])") "a")
> $5 = ((lambda (string-871)
>    (let ((match-struct-876
>            (string-match "([a-z])" string)))
>      (if match-struct-876
>        (let ((count-880 (match:count match-struct-876)))
>          (if count-880
>            (map (lambda (n-883)
>                   (match:substring match-struct-876 n-883))
>                 (iota (#{1-}# count-880) 1))
>            #f))
>        #f)))
>  "a")
>
> And we see that string is not managed correctly. Is this a bug? I
> can't understand why this is not treated as intended!

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.

-- 
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"



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: and-let* is not composable?
  2013-09-09 21:34   ` Ian Price
@ 2013-09-10 13:42     ` Stefan Israelsson Tampe
  2013-09-10 13:51       ` Ian Price
  0 siblings, 1 reply; 4+ messages in thread
From: Stefan Israelsson Tampe @ 2013-09-10 13:42 UTC (permalink / raw)
  To: Stefan Israelsson Tampe, guile-user, guile-devel

[-- Attachment #1: Type: text/plain, Size: 3372 bytes --]

Ahh, I thought we nuked the unhygienic macros in our tool-chain, That is a
BUG!

Anyway can I suggest a Bug report where we
1) Make the unhygienic define-macros in the following files hygienic,
-------------------------------------------------
module/srfi/srfi-4.scm:
module/srfi/srfi-69.scm:
module/srfi/srfi-4/gnu.scm:
module/system/base/syntax.scm:
module/system/base/language.scm:
module/system/base/lalr.upstream.scm:
module/statprof.scm:
module/oop/goops.scm:
module/oop/goops/save.scm:
module/oop/goops/accessors.scm:
module/texinfo/plain-text.scm:
module/ice-9/i18n.scm:
module/ice-9/time.scm:
module/ice-9/serialize.scm:
module/ice-9/session.scm:
module/ice-9/optargs.scm:
module/scripts/snarf-check-and-output-texi.scm:
module/scripts/lint.scm:
module/sxml/ssax/input-parse.scm:
module/sxml/transform.scm:
module/sxml/upstream/SXPath-old.scm:
module/sxml/upstream/SSAX.scm:;
module/language/tree-il/primitives.scm:
module/language/ecmascript/base.scm:
module/language/assembly/disassemble.scm:
module/rnrs/bytevectors.scm:

And also change the defmacro forms in,
---------------------------------------------------------
module/system/base/lalr.scm:
module/texinfo/reflection.scm:
module/ice-9/and-let-star.scm:
module/ice-9/calling.scm:
module/ice-9/expect.scm:
module/ice-9/optargs.scm:
module/scripts/generate-autoload.scm:
module/scripts/generate-autoload.scm:

/Stefan




On Mon, Sep 9, 2013 at 11:34 PM, Ian Price <ianprice90@googlemail.com>wrote:

> Stefan Israelsson Tampe <stefan.itampe@gmail.com> writes:
>
> > (use-modules (srfi srfi-2))
> > (use-modules (srfi srfi-1))
> >
> > (define-curried (string-matches pattern string)
> >    (and-let* ((match-struct (string-match pattern string))
> >                  (count (match:count match-struct)))
> >       (map (lambda(n)(match:substring match-struct n))
> >          (iota (1- count) 1))))
> >
> > scheme@(guile-user)> (string-matches "([a-z])" "a")
> > $4 = ("a")
> >
> >
> > ,exp ((string-matches "([a-z])") "a")
> > $5 = ((lambda (string-871)
> >    (let ((match-struct-876
> >            (string-match "([a-z])" string)))
> >      (if match-struct-876
> >        (let ((count-880 (match:count match-struct-876)))
> >          (if count-880
> >            (map (lambda (n-883)
> >                   (match:substring match-struct-876 n-883))
> >                 (iota (#{1-}# count-880) 1))
> >            #f))
> >        #f)))
> >  "a")
> >
> > And we see that string is not managed correctly. Is this a bug? I
> > can't understand why this is not treated as intended!
>
> 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.
>
> --
> 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"
>

[-- Attachment #2: Type: text/html, Size: 4799 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: and-let* is not composable?
  2013-09-10 13:42     ` Stefan Israelsson Tampe
@ 2013-09-10 13:51       ` Ian Price
  0 siblings, 0 replies; 4+ messages in thread
From: Ian Price @ 2013-09-10 13:51 UTC (permalink / raw)
  To: Stefan Israelsson Tampe; +Cc: guile-user, guile-devel

Stefan Israelsson Tampe <stefan.itampe@gmail.com> writes:

> Ahh, I thought we nuked the unhygienic macros in our tool-chain, That
> is a BUG!

It is, but the issue is going to be around for as long as Guile users
themselves write unhygienic macros. And it is important to note that
just because you are using syntax-case[0], doesn't mean you are writing
hygienic macros. One of my first patches to Guile was hygiene fixes in
the define-record-type form in (rnrs records syntactic).

Fixing it in our own backyard is a start, but there is no need to do it
all at once, and it could be some nice low hanging fruit for new
contributors.

> Anyway can I suggest a Bug report where we
Then add it to the tracker :)

0.  syntax-rules is fine, modulo al petrofsky/oleg style craziness
-- 
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"



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-09-10 13:51 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CAMFYt2Z2qxkdrf1WOGZ4FowoAxLY8vtLUB-nAprg_fi2_sbCew@mail.gmail.com>
2013-09-09 20:26 ` and-let* is not composable? Stefan Israelsson Tampe
2013-09-09 21:34   ` Ian Price
2013-09-10 13:42     ` Stefan Israelsson Tampe
2013-09-10 13:51       ` Ian Price

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).