背景:
我打算为我正在开发的代码生成调试消息。我写了一个宏来避免在每个函数中编写日志调用。我知道这限制了生成更多自定义调试消息的能力,但作为回报,它将日志记录与代码隔离开来。这就是我的目标。这种宏方法也有其他缺点,例如它将函数绑定的创建仅限于该宏,但我认为我可以接受。
以下是宏的定义和演示其用法的示例。
(define-syntax (define-func stx)
(syntax-case stx ()
[(define-func (func-name args ...) body1 body2 ...)
(if (and (identifier? #'func-name)
(andmap symbol? (syntax->datum #'(args ...))))
(syntax (define (func-name args ...)
(log-debug (format "Function-name ~a:" (syntax-e #'func-name)) (list args ...))
body1
body2 ...))
(raise-syntax-error 'define-func "not an identifier" stx))]
[else (raise-syntax-error 'define-func "bad syntax" stx)]))
(define-func (last l)
(cond [(null? l) null]
[(null? (rest l)) (first l)]
[else (last (rest l))]))
(define-func (main)
(last (list 1 2 3 4 5 6 7 8 9))
(logger))
log-debug 和 logger 在单独的模块中定义
产生的输出有点像以下:
Function-name last:
args:
:-> (7 8 9)
Function-name last:
args:
:-> (8 9)
Function-name last:
args:
:-> (9)
现在我想让它更具可读性。通过可读性,我的意思是提供某种缩进,以便阅读日志的人可以理解呼叫流程。例如如下所示:
Function-name last:
args:
:-> (7 8 9)
Function-name last:
args:
:-> (8 9)
Function-name last:
args:
:-> (9)
更容易弄清楚谁打电话给谁等等。我有一个想法可以做到这一点。它涉及一个跟踪缩进的变量,然后在记录函数名称之后,我将增加缩进,在评估主体之后,在返回值之前减少值。如下所示:
(define indent 0)
(define-syntax (define-func stx)
(syntax-case stx ()
[ (... ...)
(...
(log-debug ...)
(increment indent)
(let [(retval (body1 body2 ...)]
(decrease indent)
retval))]))
increment 和 reduction 分别增加和减少缩进。
问题:
它甚至适用于返回 void 的函数。我不确定它是否是正确的行为。在球拍中 void 是一个特殊值,但我不确定创建与 void 的绑定是正确的方法。
有没有更好的方法来实现同样的目标?如果没有,这个设计有什么问题吗?只要他们将日志记录和代码分开,我对任何想法/更改都持开放态度。
谢谢您的帮助!