tutorial-syntax-case.scm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. ;;; ================
  2. ;;; WHY syntax-case?
  3. ;;; ================
  4. ;; 1. syntax-case is able to match a form only if it is an identifier
  5. ;; 2. to be able to use "guard clauses"
  6. ;; You can ask if something (a syntax-object) the macro was given is an identifier with:
  7. ;; (identifier? some-syntax-object)
  8. ;; Even in guard clauses one needs to use:
  9. ;; (identifier? (syntax something))
  10. ;; instead of:
  11. ;; (identifier? something)
  12. ;; because identifier? needs the context information of a syntax object.
  13. ;; Here is an example for using the identifier? predicate:
  14. ;; The first macro is very simple and simply adds 1 to any expression it gets.
  15. (define-syntax add1
  16. (lambda (x)
  17. (syntax-case x ()
  18. ((_ exp)
  19. (syntax (+ exp 1))))))
  20. ;; The second macro in effect filters the add1 macro, by only allowing
  21. ;; identifiers through usage of a guard clause.
  22. (define-syntax add1!
  23. (lambda (x)
  24. (syntax-case x ()
  25. [(add1! var) ; pattern matching
  26. (identifier? (syntax var)) ; guard clause
  27. (syntax (set! var (add1 var)))])))
  28. (define foo 0)
  29. (add1! foo) ; foo -> 1
  30. (add1! "not-an-identifier") ; -> error
  31. ;; The following does not work:
  32. ;; "The reason that this doesn’t work is that, by default, the expander will
  33. ;; preserve referential transparency; the then and else expressions won’t have
  34. ;; access to the binding of it."
  35. (define-syntax aif
  36. (lambda (x)
  37. (syntax-case x ()
  38. [(aif test then else)
  39. (syntax (let ((it test)))
  40. (if it then else))])))
  41. ;; =========
  42. ;; EXAMPLE 1
  43. ;; =========
  44. ;; using syntax-case - a first example
  45. (define-syntax when
  46. (syntax-rules ()
  47. ((_ test e e* ...)
  48. (if test (begin e e* ...)))))
  49. (define-syntax when
  50. (lambda (x) ; wrap it in a lambda when using
  51. ; syntax-case
  52. ; "[...] the lambda wrapper is simply a
  53. ; leaky implementation detail."
  54. (syntax-case x () ; The first argument is not the
  55. ; ellipsis identifier anymore.
  56. ; In parens are probably still the literals.
  57. ; "[...] syntax transformers are just
  58. ; functions that transform syntax to syntax.
  59. ((_ test e e* ...) ; One can apparently still use _ instead of
  60. ; a name.
  61. #'(if test (begin e e* ...)) ; #' is equivalent to (syntax <?>)
  62. ))))
  63. ;; is equivalent to:
  64. (define-syntax when
  65. (lambda (x)
  66. (syntax-case x ()
  67. ((_ test e e* ...)
  68. (syntax (if test
  69. (begin e e* ...)))))))
  70. ;; =========
  71. ;; EXAMPLE 2
  72. ;; =========
  73. ;; How are syntax-case macros more powerful than syntax-rules macros?
  74. (define-syntax add1
  75. (lambda (x)
  76. (syntax-case x ()
  77. ((_ exp)
  78. (syntax (+ exp 1))))))
  79. ;; relying on previous add1 definition
  80. (define-syntax add1!
  81. (lambda (x)
  82. (syntax-case x ()
  83. [(_ var) (identifier? (syntax var))
  84. ;; (1) apparently one can define conditions here --> guard clause!
  85. ;; (2) `identifier?` asks if a syntax object is an identifer.
  86. ;; To the expander `var` is more than only a symbol.
  87. ;; This way `identifer?` can know about this.
  88. (syntax (set! var (add1 var)))])))
  89. (define foo 0)
  90. (add1! foo) ; foo ⇒ 1
  91. (add1! "not-an-identifier") ; ⇒ error
  92. ;; =========
  93. ;; EXAMPLE 3
  94. ;; =========
  95. ;; For example, in
  96. ;; (aif (foo) (bar it))
  97. ;; `it`
  98. ;; would be bound to the result of
  99. ;; (foo).
  100. ;; (aif (foo) (bar it))
  101. ;; --v-- ^
  102. ;; | |
  103. ;; `-->-->--´
  104. ;; result goes here
  105. ;;
  106. ;; The following doesn't work:
  107. (define-syntax aif
  108. (lambda (x)
  109. (syntax-case x ()
  110. [(_ test then else)
  111. (syntax
  112. (let ((it test))
  113. (if it then else)))])))