(define-syntax syntax1
(syntax-rules ()
((syntax2 arg1 arg2 ... param ...)
(append
(syntax2 arg1 arg2 ... param)
...)
)
)
)
(define-syntax syntax2
(syntax-rules ()
((syntax2 arg1 arg2 ... param)
;Body just returns a list
)
)
)
I would like to call syntax2 for however many params there are. The error I get is that the second ellipsis is misplaced. But it follows param, so I am not sure. My logic is that the (syntax2 arg1 arg2 ... param) is repeated due to the second set of ellipses, but with param replaced by param2.
Thank you.
Related
I am trying to define a macro in LISP, such as this caller function in a different file
(set_name name My name is Timmy)
(set_name occupation I am a doctor )
(defmacro set_name (list)
(print list)
)
Just like in ordinary functions, use &rest to collect all the remaining arguments into a list.
(defmacro set_name (name &rest list)
`(setq ,name ',list))
(set_name occupation I am a doctor)
(print occupation)
This will print (I AM A DOCTOR)
You need to quote ,list in the expansion so it won't try to evaluate all the symbols as variables.
The following function outputs Hello, world
(defun helloworld ()
(format t "Hello, world"))
Function A calls function B, passing it the helloworld function:
(defun A ()
((B #'helloworld)))
Function B returns a lambda function, which invokes the function passed to B:
(defun B (fn)
(#'lambda ()
(funcall fn)))
Unfortunately, it's not working. Presumably I am doing something incorrect in function A. How do I get this to work please?
You need to use funcall in function A since the return value of function B is not in the function namespace:
? (defun helloworld ()
(format t "Hello, world"))
HELLOWORLD
? (defun B (fn)
(lambda () (funcall fn)))
B
? (defun A ()
(funcall (B #'helloworld)))
A
? (a)
Hello, world
NIL
?
Here is some more reading on the subject.
You seem to understand it in an wrong way. The first item of every list form is not going to be evaluated in the same way as the rest of the items. The first expression of list forms must be either a symbol (as in (+ 1 2)), or a lambda expression (as in ((lambda (x y) (+ x y)) 1 2)). That means, that you cannot use anything like ((B #'helloworld)). Instead you should use the function object, returned from (B #'helloworld), as an argument, passed to funcall.
Just to understand how the Scheme macros work i'm trying to define a new command, sum that works exactly like the common operator + (i.e. also undefined number of parameters).
I wroter this code:
(define-syntax sum
(syntax-rules ()
((_ arg1 arg2 args...)
(sum (+ arg1 arg2) args...))
((_ arg1 arg2)
(+ arg1 arg2))
((_ arg1)
arg1)))
It works if i pass it 1, 2 or 3 arguments. But with 4 arguments i get this error:
sum: bad syntax in: (sum 1 2 3 4)
I tried to expand the macro step-by-step with DrRacket but it stops immediately.
Can someone explain me the cause of this error?
In Scheme, ... is just another identifier, so you need a space between args and the ellipses (...) in both places, like this:
(define-syntax sum
(syntax-rules ()
((_ arg1 arg2 args ...)
(sum (+ arg1 arg2) args ...))
___etc___))
BTW, you don't need to create macros in order to accept arbitrary numbers of arguments. You can also use "rest args":
(define (sum . args)
;; args is bound to a list of all the arguments
(foldl + 0 args))
I've just started diving into Racket macros, and am trying to make a terse simple-macro-defining macro. I would like to expand an expression like this:
(macro id
(param) replacement1
(params ...) replacement2)
Into something like this:
(define-syntax id
(syntax-rules ()
((id param) replacement1)
((id params ...) replacement2)))
So the cddr of the original expression is turned into pairs of expressions (for use in the syntax-rules body), and the id is inserted into the car of each of these pairs.
I'm having trouble thinking recursively when using only the pattern-matching provided by syntax-rules (I keep wanting to manipulate the expression as though it were a normal list). What kind of pattern should I use? Or, can I somehow manipulate it as a normal list, and then unquote the result for use in the expansion?
Many thanks
Edit - tentative solution, informed by Taymon's answer
Part of my curiosity here was about getting rid of those pairing parentheses. I looked into syntax-case, but got a bit confused, so tried to do it purely with the pattern-matching sub-language. I ended up using Taymon's macro combined with another macro to 'pairize' the given templates (it acts kind of like an accumulator function):
(define-syntax-rule (macro-aux id ((param ...) expr) ...)
(define-syntax id
(syntax-rules ()
((id param ...) expr)
...)))
(define-syntax pairize
(syntax-rules ()
((pairize id (pairs ...) p b) (macro-aux id pairs ... (p b)))
((pairize id (pairs ...) p b rest ...) (pairize id (pairs ... (p b)) rest ...))))
(define-syntax macro
(syntax-rules ()
((macro id tpl-expr ...) (pairize id () tpl-expr ...))))
It is possible to build a macro expander that manipulates the syntax expression as regular Racket data. However, that's not really necessary in this case.
One thing I would recommend is changing your syntax slightly, so that each pattern-replacement pair is enclosed in brackets. Like this:
(macro id
[(param) replacement1]
[(params ...) replacement2])
Once that's done, you can just use a regular pattern-matching macro. Here's my take on it:
(define-syntax-rule (macro id [(param ...) replacement] ...)
(define-syntax id
(syntax-rules ()
[(id param ...) replacement] ...)))
Taymon is right, but it is also possible to do it with ellipses without wrapping the pattern-replacement pairs in brackets, using ~seq from syntax/parse:
(require syntax/parse/define)
(define-simple-macro (macro id (~seq (param ...) replacement) ...)
(define-syntax id
(syntax-rules ()
[(id param ...) replacement] ...)))
Which can be used like you originally wanted:
(macro id
(param) replacement1
(params ...) replacement2)
The code below doesn't behave as I would expect.
; given a function name, its args and body, create 2 versions:
; i.e., (double-it foo []) should create 2 functions: foo and foo*
(defmacro double-it
[fname args & body]
`(defn ~fname ~args ~#body)
`(defn ~(symbol (str fname "*")) ~args ~#body))
The code above doesn't create two functions as I would expect. It only creates the last one.
user=> (double-it deez [a b] (str b a))
#'user/deez*
How can I get a single macro to define two functions?
; given a function name, its args and body, create 2 versions:
; ie (double-it foo [] ) should create 2 functions: foo and foo*
(defmacro double-it
[fname args & body]
`(do (defn ~fname ~args ~#body)
(defn ~(symbol (str fname "*")) ~args ~#body)))
(double-it afunc [str] (println str))
(afunc* "asd")
(afunc "asd")
No need to quote them separately.