So it begins: I finally started implementing permutation group algorithms in. In good programmer tradition, I seem to find all the ways to stumble.
The macro one
Since macros are cool, I thought I’d implement a macro to swap two entries in a vector. The question whether I should be using a macro here is beside the point. Like so:
(require syntax/parse/define) (define-simple-macro (swap v i j) (let [(tmp (vector-ref v i))] (vector-set! v i (vector-ref v j)) (vector-set! v j tmp)))
This even works, if I test it on the repl
> (define v (build-vector 15 (λ(x) x))) > (display v) #(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) > (swap v 0 1) > (display v) #(1 0 2 3 4 5 6 7 8 9 10 11 12 13 14)
Except, if you know how macros work which I should have, I attended the brilliant , you will find this macro has a bug. school, and we were warned about it
I needed to do to make random permutations, so I’d do something like this.
> (define v (build-vector 15 (λ(x) x))) > (display v) #(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) > (swap v (random 15) 0) > (display v) #(10 1 2 3 4 5 6 7 0 9 10 11 12 13 14)
Now this is odd isn’t it? It looks odd until you realise that macro expansion just replaces every occurrence of
i in the macro by
(random 15), and hence the above call expands into
(let [(tmp (vector-ref v (random 15))] (vector-set! v (random 15) (vector-ref v 0)) (vector-set! v 0 tmp))
Which is most certainly incorrect. The solution is to make sure that arguments are only evaluated once, and everything is good.
(require syntax/parse/define) (define-simple-macro (swap v i j) (let* [(i_ i) (j_ j) (tmp (vector-ref v i_))] (vector-set! v i_ (vector-ref v j_)) (vector-set! v j_ tmp)))
Bonus: The invisible hyphen one
While writing this post, I tried copy-and-pasting code into my DrRacket session to make sure it works, and DrRacket kept complaining at me about
define-simple-macro not being an identifier. Turns out that I setup pollen to process the whole page with hyphenate which inserts invisible hyphens into all the things, including the code snippets. Damn you unicode.