How to tranpose pattern sequence in Scheme macro? - macros

I wrote the following Scheme macro.
(define-syntax join
(syntax-rules ()
((join (var ...) (val ...) ...)
'(((var val) ...)
...))))
When I try it
(join (a b c)
(1 2 3)
(2 4 6)
(3 6 9))
it returns the following result.
(((a 1) (a 2) (a 3))
((b 2) (b 4) (b 6))
((c 3) (c 6) (c 9)))
But my intention was to write a macro, which returns the following result.
(((a 1) (b 2) (c 3))
((a 2) (b 4) (c 6))
((a 3) (b 6) (c 9)))
How the transpose the way the pattern matcher itemizes the var variable?
Update: I was told, that the join macro in this question is illegal according to R7RS 4.3.2:
Pattern variables that occur in subpatterns followed by one or more
instances of the identifier ⟨ellipsis⟩ are allowed only in subtemplates
that are followed by as many instances of ⟨ellipsis⟩.

Sorry but I got it myself. This seems to work.
(define-syntax join
(syntax-rules ()
((_ var val ...)
(let-syntax ((j (syntax-rules ::: ()
((_ (k :::) (v :::))
'((k v) :::)))))
`(,(j var val) ...)))))

Related

Scheme macro - Expand a list into a set of function calls

This procedure to identify that a tic-tac-toe row is marked does not work (X _ _ row is identified as fully marked when it is not)
(define (won? b m)
(define (row-marked? r)
(every?-ec (:vector c (index i) b) (if (memv i r)) [char=? c m]))
"Returns #t if the mark m won"
(let ([rr '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))])
`(or ,#(map (lambda (r) `(row-marked? (list ,#r))) rr))))
while the procedure below works
(define (won? b m)
(define (row-marked? r)
(every?-ec (:vector c (index i) b) (if (memv i r)) [char=? c m]))
"Returns #t if the mark m won"
(or (row-marked? '(0 1 2)) (row-marked? '(3 4 5)) (row-marked? '(6 7 8))
(row-marked? '(0 3 6)) (row-marked? '(1 4 7)) (row-marked? '(2 5 8))
(row-marked? '(0 4 8)) (row-marked? '(2 4 6))))
I've tried with no luck
(let ([rr '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))])
`(or ,#(map (lambda (r) `(row-marked? ,r)) rr)))
and
(let ([rr '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))])
`(or ,#(map (lambda (r) `(row-marked? ',r)) rr)))
as well. What I'm doing wrong?
My goal is to avoid code repetition and automatically generate the executable (or ...) expression while keeping the short-circuiting of both or and every-ec
Thank you!
What you need isn't a macro (and as you've specified it it can not be done by a macro), it's SRFI 1's any function:
(define (won? b m)
(define (row-marked? r)
(every?-ec (:vector c (index i) b) (if (memv i r)) [char=? c m]))
"Returns #t if the mark m won"
(any row-marked?
'((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))))
A single-list version of any, which is all you need, is very easy to write:
(define (any/1 p l)
(if (null? l)
#f
(or (p (first l))
(any/1 p (rest l)))))
A fully-fledged any is a bit harder to get right, especially if you want it to be efficient in the simple cases.
It's worth while perhaps seeing why what you want to achieve can't be done with a macro. If you consider the fragment
(let ([rr ...])
(m row-marked? rr))
Then can m be a macro whose expansion is (or (row-marked ...) ...)? No, it can't be, because macros transform source code and the list which is bound to rr is not available until run time: the macro does not have the source code it needs to transform.
Really, the thing you want to avoid here, is that the forms in the body of row-marked? should be evaluated only as many times until they return true, and the mechanism for doing that is just wrapping them up in a function and calling it only as many times as needed.
However that mechanism is sometimes a bit syntactically clumsy: if I have something like
(any (λ (e1 e2)
(and (integer? e1) (integer? e2)
(even? e1) (even? e2))
(not (= e1 e2)))
l1 l2)
I might rather write this as
(finding-first ((e1 l1) (e2 l2))
(and (integer? e1) (integer? e2)
(even? e1) (even? e2)
(not (= e1 e2))))
And, of course, you can:
(define-syntax finding-first
(syntax-rules ()
[(_ ((v l) ...) form ...)
(any (λ (v ...) form ...) l ...)]))

LISP - Write the function (REMOVE EL), that removes given atom or list from another list on all levels of the list

I have the following task:
To build the function (REMOVE EL), that removes given atom or list from another list, and this should apply on each level of the list
Example :
L=(A B A (B A C X ) X B)
(REMOVE A L ) -> (B (B C X) X B)
I wrote the following code :
(defun removeel(el tree)
(mapcan (lambda(subtree)
(cond ((null subtree) (list nil))
((consp subtree) (list (removeel el subtree)))
((eql subtree el) nil)
(t (list subtree))))
tree))
The problem is that when I remove atom, it works excellent
(removeel 'B' (A B A (B A C X ) X B))
(A A (A C X) X)
But it doesn't work If I want to remove a list
(removeel '(B A C X) ' (A B A (B A C X ) X B))
(A B A (B A C X) X B)
What should be done to make it to remove lists too ?
the simplest way would be to introduce optional equality test function, as in remove standard procedure.
it could look this way:
(defun rem-rec (item data &key (test #'eql))
(mapcar (lambda (x) (if (listp x)
(rem-rec item x :test test)
x))
(remove item data :test test)))
CL-USER> (rem-rec 1 `(1 2 (3 4 (1 2 3)) (1 (1 2 3) 3 4)))
;;=> (2 (3 4 (2 3)) ((2 3) 3 4))
for lists equality you can use equal (or equalp or anything more specific)
CL-USER> (rem-rec '(1 2 3) '(1 2 (3 4 (1 2 3)) (1 (1 2 3) 3 4)) :test #'equal)
;;=> (1 2 (3 4) (1 3 4))

In Racket, how do I create a syntax rule which can deal with multiple of one parameter?

Kind of difficult to word the question in the title.
(define-syntax func
(syntax-rules ()
((func a b c (d e) ...) (cond ((and (not (empty? d)) (not (empty? e))) (+ d e))
)
)
)
)
If someone calls (func a b c (1 1) (2 2)), I would like it to add all d's and e's together. First, my code above produces an error
syntax: missing ellipsis with pattern variable in template in: d
and if it didn't even give me that error, I'm not even sure if it would add all of them together. I would also like it to do other things in case d and e were not provided, so I put it in a cond.
Thank you.
Edit:
(define-syntax func
(syntax-rules ()
((func a b c (d e) ...)
(cond
((and
(not (empty? d))
(not (empty? e)))
(+ d e))))))
The pattern something ... will match zero or more elements. Thus in you pattern (func a b c) will match the rule.
If a pattern has elipses in the pattern it needs elipses in the expansion. Eg.
(define-syntax test
(syntax-rules ()
((_ a b ...)
(if a (begin #t b ...) #f))))
(test 1) ; ==> #t
(test 1 2) ; ==> 2
(test #f 2) ; ==> #f

Racket / Scheme - Syntax-Case

I'm currently working on an assigment about racket macros. In one of the questions we`re asked to define a macro my-set! which acts like this:
(define x 3)
(define y 5)
(define z 7)
(my-set! (x (+ x y)))
(my-set! (x (+ x y)) (z 6))
x
13
y
5
z
6
I found this interesting document on syntax-case http://www.cs.indiana.edu/~dyb/pubs/tr356.pdf
Currently my macro works but i'm trying to add a "fender" like on page 10 of the document to fend off errors like if one of the variables arent identifiers or anything else.
Here`s my code:
(define-syntax my-set!
(letrec ((all-ids?
(λ (ls)
(or (null? ls)
(and (identifier? (car ls))
(all-ids? (cdr ls)))))))
(lambda (x)
(syntax-case x ()
((_ (var val) (var2 val2) (var3 val3) ...)
(all-ids? (syntax (var var2 var3 ...)))
(syntax (begin (set! var val) (my-set! (var2 val2) (var3 val3) ...))))
((_ (var val))
(syntax (set! var val)))))))
If I test this exact code without the fender, it works perfectly. But when I run this:
(define a 1)
(define b 1)
(define c 1)
(my-set! (a 3) (b 4) (c 5))
I get this:
car: contract violation expected: pair?
given: syntax:C:\Users\mgiroux\Desktop\define-myset.rkt:40:26 (a b c)
Seems like all-ids? cant (car) of (a b c) cause its not a list? I tried passing it as a list but didnt work either, i seem to have copied exactly the way they do it in the pdf I linked.. What am I missing here?
#'(var var2 var3 ...) is indeed not a list. It's a syntax object that wraps a list. You should use syntax->list to extract out the items into a list, thus your guard should look like:
(all-ids? (syntax->list #'(var var2 var3 ...)))

Append for mutable variables

Is there built in function or macro to append list to a mutable list. Something like PUSH, but slightly different.
Here is the PUSH using exapmle:
(setq v '(3))
(push '(1 2) v) ;v now ((1 2) 3)
And I need fallowing behavior:
(setq v '(3))
(mappend '(1 2) v) ;v should be (1 2 3)
I think you are looking for nconc?
[Function] nconc &rest lists
nconc takes lists as arguments. It returns a list that is the
arguments concatenated together. The arguments are changed rather than
copied. (Compare this with append, which copies arguments rather than
destroying them.) For example:
(setq x '(a b c)) (setq y '(d e f)) (nconc x y) => (a b c d e f) x
=> (a b c d e f)
You could use nconc to define a pushlist macro, to have an interface analogous to push:
(defmacro pushlist (lst place)
`(setf ,place (nconc ,lst ,place)))
And test it:
CL-USER>
(defparameter *v* (list 3))
*V*
(pushlist (list 1 2) *v*)
CL-USER>
(1 2 3)
CL-USER>
*v*
(1 2 3)
CL-USER>
Also note that I'm using (list 3), instead of '(3), after reading sigjuice's comment.