Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Macros in Racket [Scheme][newbie][help]

Name: Anonymous 2011-02-28 20:17

Hi /prog/. So I've only just picked up Racket and I want to write some macros to use with an SQL database.

I'd like:
(wrapper wrapper-id
  [query-id "SQL"]
  [query-id "SQL" f ...])

to define a procedure make-wrapper-wrapper-id, which I would then use to create some value which would contain the prepared sql statements, and lambdas to apply to the results of the queries.

Then after doing
(define some-wrapper (make-wrapper-... ...)),
I'd like to say:
(some-wrapper :: query-id param ...)
to automatically invoke the statement associated with query-id and apply the stored lambda to the result.

My implementation (prepare and execute provided by the DB module):
(define-syntax mk-f
  (syntax-rules ()
    [(mk-f) (lambda (%) %)]
    [(mk-f f ...) (lambda (%) (f ... %))]))

(define-for-syntax (mk-spec form)
  (let* ([def (syntax->list form)])
    (with-syntax ([id (car def)]
                  [sql (cadr def)]
                  [(f ...) (cddr def)])
      #'(list* 'id sql (mk-f f ...)))))

(define-for-syntax (mk-c-id id)
  (string->symbol (string-append "make-wrapper-" (symbol->string (syntax->datum id)))))

(define-syntax (wrapper stx)
  (syntax-case stx ()
    [(wrapper id defs ...)
     (with-syntax ([c-id (mk-c-id #'id)]
                   [(spec ...) (map mk-spec (syntax->list #'(defs ...)))])
       #'(define (c-id connect)
           (make-wrapper connect (list spec ...))))]))

(define (make-wrapper connect specs)
  (let* ([conn (connect)]
         [f (lambda (x) (list (car x) (cons (prepare #:connection conn (cadr x)) (cddr x))))])
    (cons conn (hash (append-map f specs)))))

(define-syntax ::
  (syntax-id-rules ()
    [(w :: id param ...)
     (exec-query w (quote id) param ...)]))

(define (exec-query wrapper id . params)
  (let ([m (hash-ref (cdr wrapper) id)])
    ((cdr m) (execute (car m) params))))

But, well, it doesn't work. I've stepped through the (wrapper ...) macro in DrRacket and it expands just right, but it's like the define does nothing; I can't reference make-wrapper-wrapper-id at all! And using the :: macro causes a bad syntax error.
It's rather late and I'd really appreciate your help, guys!

Name: Anonymous 2011-02-28 21:06

Your first problem is very simple. Your function mk-c-id is creating a symbol (wrong), which is then given the wrong context when turned into syntax by with-syntax. The fix is to change it's definition to,
(define-for-syntax (mk-c-id id)
  (datum->syntax id (string->symbol (string-append "make-wrapper-" (symbol->string (syntax->datum id)))))

so that it creates a syntax object with the correct context.

Name: Anonymous 2011-02-28 21:22

>>2
Thank you! I was sure that with-syntax converted the right-hand-side of a binding into a syntax, but changing mk-c-id to accept the stx from the syntax-case and doing a (datum->syntax stx ...) in there made it work.

That only leaves the second problem. I wonder if it's at all possible to establish that sort of syntax rule, since the only example I found in the docs used a literal set! in the pattern.

Name: Anonymous 2011-02-28 21:50

If you add in a second rule [m #t], you will see that your pattern doesn't match. This is because identifier syntax (I'm specifically thinking of R6RS MAKE-VARIABLE-TRANSFORMER but this seems to be roughly the same) isn't supposed to be used for macros in an arbitrary position, but for 3 specific use cases.
1. Keyword on it's own
2. Keyword as the CAR of an expression
3. Keyword as the CADR of a SET! expression

Here's a handy guide

(define-syntax cocks
  (make-variable-transformer
   (lambda (stx)
     (syntax-case stx (set! omg-an-id)
       [(set! foo bar)
        #''set!]
       [(cocks omg-an-id)
        #''omg-an-id]
       [(cocks not-an-id)
        #''not-an-id]
       [cocks
        (identifier? #'cocks)
        #''all-by-myself]))))

(list (set! cocks foo)
      (cocks omg-an-id)
      (cocks are-so-fucking-cock-like)
      cocks)
;; will expand to
(list 'set! 'omg-an-id 'not-an-id 'all-by-myself)
;; although you will need to change a setting in Racket's expander to get the first one as it won't expand SET! by default
;; or you can check it with Guile's or Ikarus' or whatever


In general though, I stay clear of identifier syntax as it seems needlessly obfuscatory.

Name: Anonymous 2011-02-28 21:57

>>4
I suspected that to be the case. It sort of sucks, but it's not like changing :: to an ordinary procedure and using it like (:: ...) is that much of a deal.
Thanks!

Name: Anonymous 2011-02-28 22:49

>>4
>]))))
Five-paren depth just to define a simple macro! Enjoy your Scheme.

Name: Anonymous 2011-02-28 22:51

>>6
Not that unusual even for other lisps. I've had much deeper macros and functions myself. It's not a problem if you have a good editor.

Name: Anonymous 2011-02-28 23:02

>>6
Well, it's a Lisp, isn't it? Bitching about parens in Lisps is like bitching about having to memorize mnemonics if you want to program in assembly. It's just such a fundamental component of the language it's not worth considering it a drawback.

Name: Anonymous 2011-02-28 23:06

>>6
There are ways to do it in less parens, but this way you have the least common denominator and people using $SCHEME_THAT_SUPPORTS_SYNTAX_CASE_BUT_NOT_MY_FAVOURITE_SUGAR don't bitch.

Name: Anonymous 2011-02-28 23:11

>>7
But in other Lips your functions and macros have to do really complicated things for such amount of parens.

Name: Anonymous 2011-02-28 23:11

:GJS1M 67dcbdbce4a0b67c4b48e86a6ae29205a95e4b83024a9d947213d1231800e8d9
:46 63e45348c68114eac647285a08286270
:1298942262 1298952697

>>11
<-- check 'em dubz

Name: Anonymous 2011-02-28 23:16

>>10
Implement the exact same thing with less than 5 closing parens or shut up. Christ, what a tool.

Name: Anonymous 2011-02-28 23:19

>>8
Clojure has less parens. My own Lisp-dialect rarely needs parens at all. It all boils to core language design.


let a:1 b:2
  + a b

a pretty valid Lisp code. Of course you will need parens for nested funs

let a:1 b:2 progn
  (print (+ a b))
  (/ a b)

but no more, than in other langs

Name: Anonymous 2011-02-28 23:20

>>12
I dont know Scheme, so I wonder why it's so verbose.

Name: Anonymous 2011-02-28 23:23

And you've to write `define-syntax`, where `defstx` would suffice.

Name: Anonymous 2011-02-28 23:29

>>15
Yes and while we're at it all variable names should have 6 characters max and contain only uppercase letters; every character on the page including newlines, tabs, and spaces, should be syntax; and numbers should be in base 7.

Name: Anonymous 2011-02-28 23:34

>>14
Number of parentheses is an arbitrary, and not very useful metric for verbosity. In this case there are 5 closing parens because there are three special forms (DEFINE, LAMBDA & SYNTAX-CASE), one function (MAKE-VARIABLE-TRANSFORMER), and one template grouping for SYNTAX-CASE.

Name: Anonymous 2011-02-28 23:36

>>16
enjoy your unnecessarily-long-symbol-variable-identifiers.

Name: Anonymous 2011-02-28 23:37

>>17
In this case there are 5 closing parens because there are three special forms (DEFINE, LAMBDA & SYNTAX-CASE), one function (MAKE-VARIABLE-TRANSFORMER), and one template grouping for SYNTAX-CASE.
I'm scared already.

Name: Anonymous 2011-02-28 23:41

>>18
Are you seriously advocating for constricted variable names? In which time period are you living?

Name: Anonymous 2011-02-28 23:59

Name: Anonymous 2011-02-28 23:59

:GJS1M 67dcbdbce4a0b67c4b48e86a6ae29205a95e4b83024a9d947213d1231800e8d9
:84 d0cf2949a589421533069c75db1d348f
:1298942262 1298955584

>>12
<-- that's cool and all, but check my doubles over there

Name: Anonymous 2011-03-01 0:09

>>21
Paul Graham is the type of guy who thinks that dropping the 'e' from the 'creat' system call was a good idea.

Name: Anonymous 2011-03-01 0:18

>>23
I'm not a native english speaker, so for me identifiers are just a bunch of glyphs. The shorter they're, the better. Of course you cant make everything short, so make short the most used ones.

Name: Anonymous 2011-03-01 0:32

>>24
If that is really your view, then I hope I shall never read any of your code. Programming is hard enough without first having to translate the program into English.

Name: Anonymous 2011-03-01 0:41

>>25
Everything is subjective. And programming isn't english prose. It's just a way to describe what I need. I want this way to be succinct enough and I dont care, if anybody except machine and myself will understand me. I'm a lone wolf and I love Lisp, which gives me ability to define shortcut DSLs, inventing in process my own language.

Name: Anonymous 2011-03-01 0:41

>>26
Readability is important.

Name: Anonymous 2011-03-01 0:47

>>27
Readability is subjective.

Name: Anonymous 2011-03-01 0:58

>>28
True but a copout (as was >>27's post). In any case, this conversation is at an impasse, lets leave it here.

Name: Anonymous 2011-03-01 1:17

Name: Anonymous 2011-03-01 1:54

TOO LISP; DIDN'T READ

Name: Anonymous 2011-03-01 2:26

>>31
Have you read your IHBT Haskell Beginner Tutorial?

Name: Anonymous 2011-03-01 2:26

:GJS1M 67dcbdbce4a0b67c4b48e86a6ae29205a95e4b83024a9d947213d1231800e8d9
:32 7d45fd054d86d0365418e3a528af0829
:1298942262 1298964397

>>11
dubz

Name: Anonymous 2011-03-01 5:02

>>33
Your bot is broken. That should be:


Name: Anonymous 2011-03-01 7:40

>>26
I assume you might be the ``in Lisp'' guy.

I usually use very verbose symbols, in true CL style. This is not a problem for me as I have a good editor (Emacs/SLIME/Paredit/...) and the editor can autocomplete as well as manipulate s-expressions structurally. For example, I almost never write multiple-variable-bind, instead I just type mvb<tab>, or more traditionally m-v-b<tab>. I do the same thing for almost all my long symbols, those part of the language and libraries. Of course, this doesn't mean I will use long symbols for things I don't plan on reusing (such as local variables, which I tend to name either after what they represent, but if they don't represent anything important (such as the argument to a lamda) at all, I can use single-character identifiers; there are exceptions for this, especially if I'm writing a complex program and I have some long "monster? functions or macros for whatever reason (functions which direct a complex process which can't be reduced much would be an example).

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List