[racket] Using syntax/parse, how to accept keyword arguments in any order yet not allow duplicates?

From: J. Ian Johnson (ianj at ccs.neu.edu)
Date: Sun Apr 7 20:31:14 EDT 2013

The ~in-between pattern and its specializations ~once and ~optional are great for this purpose. Anything matching this pattern must appear in the range given in ~in-between, even in ellipsis'd contexts.
(a:id b:id (~or (~once (~seq #:key1 c:id)) (~once (~seq #:key2 d:id))) ...)

-Ian

----- Original Message -----
From: "Scott Klarenbach" <scott at pointyhat.ca>
To: "Racket mailing list" <users at racket-lang.org>
Sent: Sunday, April 7, 2013 8:23:29 PM GMT -05:00 US/Canada Eastern
Subject: [racket] Using syntax/parse, how to accept keyword arguments in any order yet not allow duplicates?



Hi there, 


I'd like to create a macro that accepts non-optional keyword arguments in any order. It should however, ensure that all the arguments are provided. Finally, it should not allow duplicates. 


So far I've only been able to solve for my first criteria. 


As a test, I have this: 



(syntax-parse stx 
[(a:id b:id (~or (~seq #:key1 c:id) (~seq #:key2 d:id)) ...) #t]) 


Now, that matches for: 
#'(a b #:key1 hey #:key2 there) 
#'(a b #:key2 there #:key1 hey) 



Which is what I want. But unfortunately it also matches: 
#'(a b #:key2 there) 


And worse: 
#'(a b #:key2 one #:key2 two #:key2 three) 


The reasons are obvious. I'm just wondering if there's a more robust way of dealing with these types of scenarios that I'm missing? I thought of combining an (~or (~and clause but that becomes very tedious, and leaves the duplicate problem unsolved. 


Thanks. 

-- 
Talk to you soon, 

Scott Klarenbach 

PointyHat Software Corp. 
www.pointyhat.ca 
p 604-568-4280 
e scott at pointyhat.ca 
200-1575 W. Georgia 
Vancouver, BC V6G2V3 

_______________________________________ 
To iterate is human; to recur, divine 
____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Posted on the users mailing list.