<div dir="ltr"><div><div><div>Hi Sean,<br><br></div>A quick remark: note that let* accepts duplicate identifiers just fine (because it is defined to bind<br>them sequentially, so the last one wins).<br></div>Wouldn't that simplify your code a lot?<br>
<br></div>Stephan<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/1/1 Sean Kanaley <span dir="ltr"><<a href="mailto:skanaley@gmail.com" target="_blank">skanaley@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
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 <i>am </i>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.<br>
<br>Here's how the macro works:<br><br><span style="font-family:courier new,monospace">> (condlet (((= 1 2) (x (princ ’a)) (y (princ ’b)))<br> ((= 1 1) (y (princ ’c)) (x (princ ’d)))<br> (t (x (princ ’e)) (z (princ ’f))))<br>
(list x y z))<br><b>CD<br>(D C NIL)</b></span><br><br>Before I post the horrible racket code, I will explain the problems I'm having with macros in general:<br><br>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.<br>
<br>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.<br>
<br>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 <b>a is not an infinitely existential StateT (Bool -> IO (StateT (Cont String) (Cont String) ())) Maybe (a1,a1'), in subexpression f . g</b>. Oh, f <$> g. <b>everything checks out now! </b>Thanks, ghci, and by the way go **** yourself you stupid Cont.<br>
<br>Anywayyyyy here is my code that works for the above example at least:<br><br><span style="font-family:courier new,monospace">(define-syntax (condlet s)<br> (let ((remove-duplicates-by<br> (λ (f l) (let R ((l l))<br>
(if (null? l)<br> null<br> (cons (car l) (R (remove* (list (car l))<br> (cdr l)<br> (λ (a b)<br>
(eq? (f a) (f b)))))))))))<br> (syntax-case s ()<br> ((_ (c) body ...)<br> (syntax-case #'c (else)<br> ((else binds ...)<br> #'(let (binds ...) body ...))<br>
((t binds ...)<br> #'(if t (let (binds ...) body ...) (void)))))<br> ((_ (c cs ...) body ...)<br> (syntax-case #'c ()<br> ((t binds ...)<br> #`(let #,(syntax-case #'(c cs ...) ()<br>
(((_ (i _) ...) ...)<br> (map (λ (i) #`(#,i null))<br> (remove-duplicates-by<br> syntax->datum<br> (syntax->list #'(i ... ...))))))<br>
(if t<br> (let (binds ...) body ...)<br> (condlet (cs ...) body ...)))))))))</span><br><br>Any help is appreciated.<br>
<br>____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
<br></blockquote></div><br></div>