tags:

views:

126

answers:

3

I have a Scheme macro and a long list, and I'd like to map the macro across the list, just as if it were a function. How can I do that using R5RS?

The macro accepts several arguments:

(mac a b c d)

The list has

(define my-list ((a1 b1 c1 d1)
                 (a2 b2 c2 d2)
                 ...
                 (an bn cn dn)))

And I'd like to have this:

(begin
   (mac a1 b1 c1 d2)
   (mac a2 b2 c2 d2)
   ...
   (mac an bn cn dn))

(By the way, as you can see I'd like to splice the list of arguments too)

A: 

Would something like

(map (lambda (l) (mac (car l) (caar l) (caaar l) (caaaar l))) mylist)

work?

cthom06
The macro accepts varargs, so the above solution results in an error.
josh
I don't see why that means you'd get an error. Do you mean that the lists, inside of my-list, might be of varying length?
Jay Kominek
@Jay Korninek the macro may manipulate what is inside a1 b1 ... since I do not think we can assume they are atomic.
Davorak
(caaaar l) may signal an error if the macro doesn't accet that many arguments. I'd like something really generic...
josh
+2  A: 

Syntactic extensions are expanded into core forms at the start of evaluation (before compilation or interpretation) by a syntax expander. -Dybvig, "The Scheme Programming Language:

A macro operates on syntax. This happens before compilation or execution. It gives you another way of writing the same code.

A function operates on variables and values (which might be lists, atoms, numbers, etc) who's value is known when the function is invoked.

So mapping a macro doesn't make sense. You're asking to invoke something (macro expansion) that already happened long ago.

If you need something to write code for you and evaluate it at runtime, then might be one of those cases where you need eval.

z5h
I believe he wants the macro expanded before compilation (right?). I'm not sure about Scheme, but I did lots of that in Common Lisp with defmacro (the code inside defmacro would use lots of other functions in order to transform S-expressions (even used global hashtables!)). A macro would define several functions...
Jay
+1  A: 

Expanding on z5h's answer of using eval, the methods below show how a map-macro macro can be written if interaction-environment in implemented in the version of R5RS in use:

(define test-list '((1 2 3 4)
                    (5 6 7 8)))

;Or if your version of scheme implments interaction-environment then:
(define-syntax trade
  (syntax-rules ()
    ((_ a b c d) (display (list b a d c)))))

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;Careful this is not really mapping. More like combined map and apply.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(define-syntax map-macro
  (syntax-rules ()
    ((_ mac ls) (let ((mac-list (map (lambda (lst) (cons 'trade lst)) ls)))
                          (eval 
                           `(begin
                              ,@mac-list)
                           (interaction-environment))))
                        ))

(map-macro trade test-list)
;outputs: (2 1 4 3)(6 5 8 7)

So that last map-macro call evaluates the following:

What ends up getting evaluated from (map-macro trade test-list) is:

(begin
  (trade 1 2 3 4)
  (trade 5 6 7 8))

Which is not quite a map, but I believe it does answers your question.

Davorak
So this basically means I can't choose to write a "map-syntax" macro that would iteratively (in the macro itself) expand until mac was expanded for all members of the list? (Of course I'd have to pass the list litarally o the macro, and not in a variable!)
josh
You can effectively write a map-macro if you have interaction-environment in your preferred version of R5RS scheme. interaction-environment is optional in the R5RS spec. It does exist in DrScheme or whatever the new name is. I edited my answer to give an example of a map-macro macro.
Davorak