[racket] Onlisp's condlet macro in Racket

From: Stephan Houben (stephanh42 at gmail.com)
Date: Wed Jan 2 08:37:03 EST 2013

Hi Sean,

A quick remark: note that let* accepts duplicate identifiers just fine
(because it is defined to bind
them sequentially, so the last one wins).
Wouldn't that simplify your code a lot?

Stephan


2013/1/1 Sean Kanaley <skanaley at gmail.com>

> While I've ultimately succeeded in having it return the correct output for
> a sample input, I'm not positive it's correct in general and I *am *positive
> it's written poorly, as I don't fully understand both syntax-case and
> syntax objects vs. datums.  If someone could look it over and provide a
> more canonical version, I would be grateful.
>
> Here's how the macro works:
>
> > (condlet (((= 1 2) (x (princ ’a)) (y (princ ’b)))
>             ((= 1 1) (y (princ ’c)) (x (princ ’d)))
>             (t (x (princ ’e)) (z (princ ’f))))
>     (list x y z))
> *CD
> (D C NIL)*
>
> Before I post the horrible racket code, I will explain the problems I'm
> having with macros in general:
>
> Problem 1, separate phases:  I have a remove-duplicates-by function that
> would be great to have globally, but it seemingly must be written locally.
>
> Problem 2: You can't use a pattern variable outside of a pattern, so you
> have to syntax-ify it with #', but then you can't access the associated
> s-exp without removing the syntax.  The way to bind things to null by
> default is to get every id and output the obvious let statement, except ids
> might be repeated so you have to remove duplicates (enter problem 1).  It's
> remove-duplicates-BY because the removal happens by syntax->datum'ing each
> identifier-syntax-thing since it can't appear outside of a pattern.
>
> Problem 2: How to remove a portion of the macro code into a separate
> transformer function?  It's kind of annoying having a whole block of code
> relegated to cleaning up the duplicate ids inside of the let it expands
> into.  That would ideally be written "let #,(remove-dups #'(c cs...))" or
> similar...some kind of sub-macro to handle just getting ids.  I thought
> that's what let-syntax or nested define syntaxes were for but I get phase
> errors or preposterous, very dark errors like "lambda not bound".  Suddenly
> I prefer Haskell's *a is not an infinitely existential StateT (Bool -> IO
> (StateT (Cont String) (Cont String) ())) Maybe (a1,a1'), in subexpression f
> . g*.  Oh, f <$> g.  *everything checks out now!  *Thanks, ghci, and by
> the way go **** yourself you stupid Cont.
>
> Anywayyyyy here is my code that works for the above example at least:
>
> (define-syntax (condlet s)
>   (let ((remove-duplicates-by
>          (λ (f l) (let R ((l l))
>                     (if (null? l)
>                         null
>                         (cons (car l) (R (remove* (list (car l))
>                                                   (cdr l)
>                                                   (λ (a b)
>                                                     (eq? (f a) (f
> b)))))))))))
>     (syntax-case s ()
>       ((_ (c) body ...)
>        (syntax-case #'c (else)
>          ((else binds ...)
>           #'(let (binds ...) body ...))
>          ((t binds ...)
>           #'(if t (let (binds ...) body ...) (void)))))
>       ((_ (c cs ...) body ...)
>        (syntax-case #'c ()
>          ((t binds ...)
>           #`(let #,(syntax-case #'(c cs ...) ()
>                      (((_ (i _) ...) ...)
>                       (map (λ (i) #`(#,i null))
>                            (remove-duplicates-by
>                             syntax->datum
>                             (syntax->list #'(i ... ...))))))
>               (if t
>                   (let (binds ...) body ...)
>                   (condlet (cs ...) body ...)))))))))
>
> Any help is appreciated.
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130102/1e194837/attachment-0001.html>

Posted on the users mailing list.