How do I define functions using Racket macros?

孤街浪徒 提交于 2019-11-28 23:56:24

The key for an answer is datum->syntax. The basic idea is that you want to take some random data and turn it into a syntax -- in this case, turn a symbol into an identifier. An identifier is basically a symbol with some lexical information that (very roughly) indicates how it is bound. Using datum->syntax you can do exactly that: it expects an existing piece of syntax which is where it copies the binding from, and a datum (a symbol here) which is the value that is contained in the syntax wrapper.

Here's an example that demonstrates a define-struct-like tool using this:

#lang scheme
;; implements a defstruct-like macro that uses association lists
(define-syntax (defstruct-lite stx)
  (syntax-case stx ()
    [(defstruct-lite name field ...)
     (let ([make-id
            (lambda (template . ids)
              (let ([str (apply format template (map syntax->datum ids))])
                (datum->syntax stx (string->symbol str))))])
       (with-syntax ([make-name (make-id "make-~a" #'name)]
                     [name?     (make-id "~a?" #'name)]
                     [(arg ...) (generate-temporaries #'(field ...))]
                     [(name-field ...)
                      (map (lambda (f) (make-id "~a-~a" #'name f))
                           (syntax->list #'(field ...)))])
         #'(begin
             (define (make-name arg ...) (list 'name (cons 'field arg) ...))
             (define (name? x) (and (pair? x) (eq? 'name (car x))))
             (define (name-field x)
               (and (name? x) (cdr (assq 'field (cdr x)))))
             ...)))]))

And here's an example of using it:

(defstruct-lite point x y)
(point-y (make-point 1 2))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!