RU beehive logo ITEC dept promo banner
ITEC 380
2008fall
ibarland

homeinfolecturesexamsarchive

lect14a
better macros

How well does this C pre-processor macro work?

#define swap(a,b)   int tmp = a; a = b; b = tmp;

It turns out this mysterious syntax-rules allows pattern-matching (just like prolog!). Here's an example, based on this page; it re-writes let as lambda, as we discussed earlier:

(define-syntax my-let
  (syntax-rules ()
    ( (my-let ((id expr) ...) body)      ; before
      ((lambda (id ...) body) expr ...)  ; after
      )))
After doing this,
(my-let {[a 3]
         [id1 5]
         [c 7]
        }
  (+ a id1 c))
; =>
((lambda (a id1 c) (+ a id1 c)) 3 5 7)
; =>
15

Some personal favorite macros:

A personal favorite macro: I often find myself writing functions of one argument, like

  ; Suppose I have a list 'data' and a threshold 'n';
  ; grab all the elements of 'data' bigger than 'n':
  (filter (lambda (x) (> x n)) data)
I do things like this so often, I'd like to have my own abbreviated version for creating a function:
  (filter (l1 > x n) data)
Note that x is an introduced variable. (We want it to shadow any existing1 variable name!) The code for this is actually pretty involved, using scheme's hygienic macro system to introduce non-hygienic macros. Therefore, the code is given only as an un-explained footnote2

Little Languages

But macros can be used for more than programmers: it can be used to introduce entire scripting languages, inside (say) Scheme! Here is an example -- taken from Krishnamurthi's manifesto Swine Before Perl: Suppose we want to implement finite state machines. While we could have our non-programming expert friends learn our own programming language plus our own libraries, or we could write a program which takes in strings and interprets them, there is a third approach: let them write something that looks like a FSM spec, but is translated directly into Scheme. For example, here's a boring traffic-light automoton

(define parity
  (automaton s00 
             (s00 T : (a -> s10)
                      (b -> s01))
             (s01 F : (a -> s11)
                      (b -> s00))
             (s10 F : (a -> s00)
                      (b -> s11))
             (s11 F : (a -> s01)
                      (b -> s10))))

(parity '(a a b a b a))    ; yields true
(parity '(a a b a b a b))    ; yields false
You can see what a scheme program would do: have a variable for the current-state, and then (depending on that state and (first input)) recur with a new value for the current state. Actually, it might even make four functions, s00, s01, s10, s11; for example s10 be a function, which given a list starting with a will (tail-)recur on s00, and given a list starting with b it will (tail-)recur on s11.
(define-syntax automaton
  (syntax-rules (-> :)
    [(automaton init-state
                (state accepting? : (cndn -> new-state) 
                                    ...)
                ...)
     (letrec ([state (lambda (input)
                       (if (empty? input)
                           (symbol=? accepting? 'T)
                           (case (first input)
                             [(cndn) (new-state (rest input))]
                             ...
                             [else false])))]  ; No listed transition: fail.
              ...)
       init-state)]))


1 Actually, I use the variable name __ instead of x, reminiscent of "fill in the blank (with the argument)": (filter (l1 > __ n) data)      

2

  (define-syntax (l1 stx)
    (syntax-case stx ()
      [(src-l1 proc args ...)
       ; This nested syntax-case is so that __ has the same
       ; context/scope as proc,args.  (That is,  we
       ; don't want to introduce a hygienic __ that is really
       ; different from any __ occuring in proc,args.)
       ; So create a syntax-object __ that takes context from src-l1,
       ; and then return a lambda which binds that __.
       ;
       (syntax-case (datum->syntax #'src-l1 '__) ()
         [__ (syntax/loc #'src-l1 (lambda (__) (proc args ...)))])]))

; There might be a cleaner way of writing the above
     

homeinfolecturesexamsarchive


©2008, Ian Barland, Radford University
Last modified 2008.Dec.10 (Wed)
Please mail any suggestions
(incl. typos, broken links)
to iba�rlandrad�ford.edu
Powered by PLT Scheme