Racket - How to define a function that can be used both in syntax transformers and ordinary code?

145 views Asked by At

I am using syntax transformers to define macros in Racket. I want to create some helper functions to help me manipulate the syntax. However, the functions I defined outside the syntax transformer are not available inside the syntax transformer. For example, in the following code

(define (my-function x) (+ x 1))

(define-syntax my-macro
  (lambda (stx)
    (datum->syntax stx (my-function (cadr (syntax->datum stx))))))

I got the error "my-function: reference to an unbound identifier at phase: 1; the transformer environment".

After some searching, I am able to write the following code so that my-function is available inside the syntax transformer.

(begin-for-syntax
  (define (my-function x) (+ x 1)))
(provide (for-syntax my-function))

(define-syntax my-macro
  (lambda (stx)
    (datum->syntax stx (my-function (cadr (syntax->datum stx))))))

But the problem is, my-function is not available outside the syntax transformer this time. Sometimes I want to check those helper functions in ordinary code, so I need to be able to call it from both inside and outside the syntax transformer, just like the function cadr. How can I achieve that?

I know my question has something to do with Racket's syntax model, in particular the concept of "phase level", but I never really understand it. If you could provide some easy-to-follow tutorials explaining it I would even be more grateful.

1

There are 1 answers

0
Sorawee Porncharoenwase On

A common way is to define your function that you want to share across phases in another (sub)module. Then, require it twice.

#lang racket

(module common racket
  (provide my-function)
  (define (my-function x) (+ x 1)))

(require 'common
         (for-syntax 'common))

(define-syntax my-macro
  (lambda (stx)
    (datum->syntax stx (my-function (cadr (syntax->datum stx))))))

(my-function 1)
(my-macro 123)