Last active
August 29, 2015 14:13
-
-
Save tfeb/0b8531c94cf685824626 to your computer and use it in GitHub Desktop.
Racket macro idiomaticity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket | |
(define (call/environment-variables thunk bindings) | |
;; This is a conventional call-with-whatever function: it calls thunk | |
;; with an environment augmented by bindings which is a list of pairs of | |
;; names and values | |
(let ([e (environment-variables-copy | |
(current-environment-variables))]) | |
(for ([b bindings]) | |
(match-let ([(list n v) b]) | |
(environment-variables-set! e n v))) | |
(parameterize ([current-environment-variables e]) | |
(thunk)))) | |
;;; My original overcomplicated version | |
;;; | |
;(define-syntax (with-environment-variables stx) | |
; ;; This is the macro. The only significant thing here is that I want everything | |
; ;; to be evaluated: both names and values of variable (I am not sure why), so | |
; ;; (w-e-v ([n v] ...) ...) -> (call/ev (λ () ...) (list (list n v) ...)) | |
; (syntax-case stx () | |
; [(_ () body ...) | |
; #'(call/environment-variables (λ () body ...) '())] | |
; [(_ (binding ...) body ...) | |
; #`(call/environment-variables | |
; (λ () body ...) | |
; (list #,@(for/list ([b (syntax->list #'(binding ...))]) | |
; (syntax-case b () | |
; [(n v) | |
; #'(list n v)]))))])) | |
;;; bmastenbrook's pretty version | |
;;; | |
;(define-syntax with-environment-variables | |
; (syntax-rules () | |
; [(_ ([name value] ...) body ...) | |
; (call/environment-variables | |
; (λ () body ...) (list (list name value) ...))])) | |
;;; My less-pretty but, I think, equivalent version | |
;;; | |
(define-syntax (with-environment-variables stx) | |
(syntax-case stx () | |
[(_ ([name value] ...) body ...) | |
#'(call/environment-variables | |
(λ () body ...) | |
(list (list name value) ...))])) | |
(module+ test | |
(require rackunit) | |
(let ([n #"FOO"] [v #"BAR"] [n2 #"FISH"] [v2 #"BAT"]) | |
(check-equal? | |
(call/environment-variables | |
(λ () (environment-variables-ref (current-environment-variables) n)) | |
`([,n ,v])) | |
v) | |
(check-equal? | |
(with-environment-variables ([n v]) | |
(environment-variables-ref (current-environment-variables) n)) | |
v) | |
(check-equal? | |
(with-environment-variables ([n v] [n2 v2]) | |
(let ([e (current-environment-variables)]) | |
(map (λ (n) (environment-variables-ref e n)) `(,n ,n2)))) | |
`(,v ,v2))) | |
(check-not-eq? | |
(with-environment-variables () (current-environment-variables)) | |
(current-environment-variables))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks: it was meant to be
#'
: the backquote got in by mistake.I should look at "Fear Of Macros": I was aware of it but had (probably incorrectly) assumed it was aimed at people who aren't used to the idea of Lisp-family macros at all, rather than people trying to grok Racket's in particular.