Skip to content

Instantly share code, notes, and snippets.

@wilbowma
Created April 15, 2024 23:47
Show Gist options
  • Save wilbowma/db5bd0ce897b4c27561ef1b4771ea1dd to your computer and use it in GitHub Desktop.
Save wilbowma/db5bd0ce897b4c27561ef1b4771ea1dd to your computer and use it in GitHub Desktop.
#lang racket
;; A well typed macro that manipulates binding (in a trivial way)
(module A racket
(require
(for-syntax
racket/function
syntax/parse
racket/syntax
syntax/transformer))
(define-syntax (elab-e e)
(syntax-parse e
[(_ (lambda (x ...) body))
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body))]))
(require rackunit)
(check-equal?
((elab-e (lambda (x) x)) 5)
5)
(check-equal?
(((elab-e (lambda (y) (lambda (x) x))) 5) 6)
6)
(check-equal?
(((elab-e (lambda (y) (lambda (x) y))) 5) 6)
5))
;; ill typed: binding error in the generated syntax
(module B racket
(require
racket/function
syntax/parse
racket/syntax
(for-syntax syntax/transformer))
(define (elab-e e)
(syntax-parse e
[(lambda (x ...) body)
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
#,(expand
#`(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body)))]))
(elab-e #'(lambda (x) x))
(require rackunit)
(check-exn values
(thunk (eval (elab-e #'(lambda (x) x)))))
)
;; ill typed: invalid use of an expansion monad operation at run-time, outside the expansion monad
(module C racket
(require
racket/function
syntax/parse
racket/syntax
(for-syntax syntax/transformer))
(define (elab-e e)
(syntax-parse e
[(lambda (x ...) body)
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
#,(syntax-local-introduce
(expand
#`(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body))))]))
(elab-e #'(lambda (x) x)))
;; ill typed: invalid use of an expansion monad operation at run-time, outside the expansion monad
(module D racket
(require
racket/function
syntax/parse
racket/syntax
(for-syntax syntax/transformer))
(define (elab-e e)
(syntax-parse e
[(lambda (x ...) body)
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
#,(local-expand
#`(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body)
'expression
'()))]))
(elab-e #'(lambda (x) x)))
;; ill typed: phase binding error
(module E racket
(require
racket/function
syntax/parse
racket/syntax
syntax/transformer)
(define (elab-e e)
(syntax-parse e
[(lambda (x ...) body)
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
#,(expand #`(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body)))]))
make-variable-like-transformer
(elab-e #'(lambda (x) x)))
;; ill typed: I honestly don't even know, but I know using expand in the
;; expansion macro is hard and usually wrong.
;; So wrong, and this errors out when the module is visited
#;(module F racket
(require
(for-syntax
racket/function
syntax/parse
racket/syntax
(for-syntax racket/base syntax/transformer)))
(define-syntax (elab-e e)
(syntax-parse e
[(_ (lambda (x ...) body))
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
#,(expand
#`(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body)))]))
(elab-e (lambda (x) x)))
;; ill typed: expanding in an unbound environment
;; raises error when module is visited
#;(module G racket
(require
(for-syntax
racket/function
syntax/parse
racket/syntax
syntax/transformer))
(define-syntax (elab-e e)
(syntax-parse e
[(_ (lambda (x ...) body))
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
#`(lambda (new-x ...)
#,(local-expand
#`(let-syntax ([x (make-variable-like-transformer #'new-x)]
...)
body)
'expression
'()))]))
(elab-e (lambda (x) x)))
;; Well typed version of G
(module H racket
(require
(for-syntax
racket/function
syntax/parse
racket/syntax
syntax/transformer))
(define-syntax (elab-e e)
(syntax-parse e
[(_ (lambda (x ...) body))
#:with (new-x ...) (map (curry format-id e "~a") (syntax->list #'(x ...)))
(define intdef (syntax-local-make-definition-context))
(define newxs (syntax-local-bind-syntaxes
(syntax->list #'(new-x ...))
#f
(syntax-local-make-definition-context)))
(with-syntax ([(new-scoped-xs ...) newxs])
#`(lambda (new-scoped-xs ...)
#,(local-expand
#`(let-syntax ([x (make-variable-like-transformer #'new-scoped-xs)]
...)
body)
'expression
'()
intdef)))]))
(require rackunit)
(check-equal?
((elab-e (lambda (x) x)) 5)
5))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment