[racket] Macros and dynamically generating identifiers
Hi there!
I'm pretty new to Racket, though not the basic concepts of functional
programming [1] Maybe I don't need macros here at all, but it seemed like
the right sort of lever when I first started, but now I'm pretty stuck[2]
and I don't understand enough about the macro system yet to be able to
figure this out.
Basically, I'm trying to make a database migration tool + relational
mapper. I'd like to be able to define my tables in an abbreviated Racket
syntax and use the definition to generate everything from the create-table
SQL scripts, a few, basic CRUD-scripts-for-all-columns to structs that will
mirror a full table row when processing the query results.
Right now, the table definition looks like this:
(define-table tickets get-all-tickets
([ticket_id serial primary-key]
[priority int nullable] ;; I believe in making not-null the default case
[description (varchar max)]
[finished_on datetime (default "9999-12-31 23:59:59.999")])
And this is pretty easy to parse into some "table" structs that describe
everything fairly sufficiently[3]:
https://gist.github.com/capnmidnight/5506674
Now, my sticking point is that I don't want to have explicitly define that
"get-all-tickets" identifier. I notice that, in my creating the "column"
struct, I've received a number of procedures for the constructor and field
accessors, all given a prefix of "column" for their identifier. So at first
glance, it seems like there are forms like struct that are capable of
dynamically defining identifiers.
So, I stepped into the definition for struct and tried to make sense of it,
but the best I could figure out was that struct used syntax-case instead of
syntax-rules. It was a bit of a hair-ball for me, I couldn't suss out the
cross references, and at least at this late of an hour I'm having trouble
understanding the documentation on syntax-case.
Specifically, I tried to do something like:
(define-syntax (double-define stx)
(syntax-case stx (double-define)
[(_ id val1 val2)
#`(begin (define id-1 val1)
(define id-2 val2))]))
(double-define id 3 7)
(displayln id-1) ;; error "id-1 unbound identifier"
(displayln id-2)
I then tried something like:
(define-syntax (double-define stx)
(syntax-case stx (double-define)
[(_ id val1 val2)
(with-syntax ([id-1 #'(string->symbol (format "~a-1" id))] ;; error
"define: not an identifier, identifier with default, or keyword for
procedure argument"
[id-2 #'(string->symbol (format "~a-2" id))])
#'(begin (define id-1 val1)
(define id-2 val2)))]))
(double-define id 3 7)
(displayln id-1)
(displayln id-2)
Clearly, not correct.
I could make the table struct into a table class and then just define a
get-all method that does what I want, but that kind of feels like giving up
and I'm more interested in using this to learn more about using macros, as
it has already done for me.
[1] Functional C# is something of a job safety program of mine :P
[2] i.e. been banging my head against the desk for the last 6 hours. I have
gotten pretty comfortable with syntax-rules though, so it wasn't a complete
waste.
[3] This isn't the final form, but I'm just pushing some code around to try
to get the basic concepts working. For example, the get-all-tickets
procedure wouldn't just return the query, it'd eventually execute it and
return the results.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130502/99f02a23/attachment-0001.html>