[英]Why define-values is not bound in a Racket macro with #lang racket/base?
[英]Macro to record evaluation steps and intermediate values in Racket?
作為學習Racket宏系統的練習,我一直在基於C ++ catch框架實現一個單元測試框架 。 該框架的功能之一是,如果我編寫如下檢查:
CHECK(x == y); // (check x y)
違反檢查時,即使所使用的宏是完全通用的,錯誤消息也會打印出x和y的值,這與其他測試框架不同,其他測試框架要求您使用諸如CHECK_EQUALS,CHECK_GREATER等宏。這可能是通過某些黑客手段實現的涉及表達式模板和運算符重載。
在我看來,在球拍中您應該能夠做得更好。 在C ++版本中,宏看不到內部子表達式,因此,如果您編寫類似以下內容:
CHECK(f(x, g(y)) == z); // (check (= (f x (g y)) z))
違反支票時,您只會找出等號左右兩側的值,而不是x,y或g(y)的值。 在球拍中,我希望應該可以遞歸到子表達式並打印出顯示評估步驟的樹。
問題是我不知道執行此操作的最佳方法是:
最好的或至少是慣用的方法是什么?
這是一些讓您入門的東西。
#lang racket
(require (for-syntax syntax/parse racket/list))
(begin-for-syntax
(define (expression->subexpressions stx)
(define expansion (local-expand stx 'expression '()))
(syntax-parse expansion
#:datum-literals (#%app quote)
[x:id (list #'x)]
[b:boolean (list #'b)]
[n:number (list #'n)]
; insert other atoms here
[(quote literal) (list #'literal)]
[(#%app e ...)
(cons stx
(append-map expression->subexpressions (syntax->list #'(e ...))))]
; other forms in fully expanded syntax goes here
[else
(raise-syntax-error 'expression->subexpressions
"implement this construct"
stx)])))
(define-syntax (echo-and-eval stx)
(syntax-parse stx
[(_ expr)
#'(begin
(display "] ") (displayln (syntax->datum #'expr))
(displayln expr))]))
(define-syntax (echo-and-eval-subexpressions stx)
(syntax-parse stx
[(_ expr)
(define subs (expression->subexpressions #'expr))
(with-syntax ([(sub ...) subs])
#'(begin
; sub expressions
(echo-and-eval sub)
...
; original expression
(echo-and-eval expr)))]))
(echo-and-eval-subexpressions (+ 1 2 (* 4 5)))
輸出:
] (+ 1 2 (* 4 5))
23
] +
#<procedure:+>
] 1
1
] 2
2
] (#%app * '4 '5)
20
] *
#<procedure:*>
] 4
4
] 5
5
] (+ 1 2 (* 4 5))
23
打印所有內容的一種替代方法是為應該顯示的內容添加一個標記。 這是一個簡單的草圖:
#lang racket
(require racket/stxparam)
(define-syntax-parameter ?
(λ(stx) (raise-syntax-error '? "can only be used in a `test' context")))
(define-syntax-rule (test expr)
(let ([log '()])
(define (log! stuff) (set! log (cons stuff log)))
(syntax-parameterize ([? (syntax-rules ()
[(_ E) (let ([r E]) (log! `(E => ,r)) r)])])
(unless expr
(printf "Test failure: ~s\n" 'expr)
(for ([l (in-list (reverse log))])
(for-each display
`(" " ,@(add-between (map ~s l) " ") "\n")))))))
(define x 11)
(define y 22)
(test (equal? (? (* (? x) 2)) (? y)))
(test (equal? (? (* (? x) 3)) (? y)))
結果如下:
Test failure: (equal? (? (* (? x) 3)) (? y))
x => 11
(* (? x) 3) => 33
y => 22
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.