[racket] Onlisp's condlet macro in Racket
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>