背景:
開発中のコードのデバッグ メッセージを生成するつもりです。各関数でロギング呼び出しを記述しないようにマクロを作成しました。これにより、よりカスタマイズされたデバッグ メッセージを生成する機能が制限されることはわかっていますが、代わりにログをコードから分離します。そして、それが私が目指しているものです。このマクロ アプローチには他にも欠点があります。たとえば、関数バインディングの作成がこのマクロのみに制限されますが、私はそれを受け入れることができると思います。
以下は、マクロの定義とその使用法を示す例です。
(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))]))
インクリメントとデクリメントは、それぞれインデントを増減します。
問題:
void を返す関数に対しても機能します。それが正しい動作かどうかはわかりません。ラケットでは void は特別な値ですが、void へのバインディングを作成することが正しい方法かどうかはわかりません。
同じことを達成するためのより良い方法はありますか? そうでない場合、この設計に問題はありますか? ロギングとコードを別々に保つ限り、私はどんなアイデア/変更にもオープンです。
助けてくれてありがとう!