とりあえず、以下の様に使える。
(import (rnrs) (core inline)) ;; map is defined in (core base) (define-inliner map (core base) ((_ p arg) (let ((proc p)) (let loop ((l arg) (r '())) (if (null? l) (reverse! r) (loop (cdr l) (cons (proc (car l)) r)))))))手続き名とそれが定義されているライブラリを指定し、実際の展開部分はsyntax-rulesのようなパターンマッチで記述する。っで、比較のためにある版とない版のコンパイル結果がこれ。
;; あり (disasm (lambda (x) (map values '(1 2 3 4 5)))) ;; size: 26 ;; 0: GREF_PUSH #<identifier user#values x80414678>; values ;; 2: CONST_PUSH (1 2 3 4 5) ;; 4: CONST_PUSH () ;; 6: LREF(2) ;; 7: BNNULL 5 ; (if (null? l) (reverse! r) (lo ... ;; 9: LREF_PUSH(3) ;; 10: GREF_TAIL_CALL(1) #<identifier reverse!#user x804146d8>; (reverse! r) ;; 12: RET ;; 13: LREF_CDR_PUSH(2) ;; 14: FRAME 4 ;; 16: LREF_CAR_PUSH(2) ;; 17: LREF(1) ;; 18: CALL(1) ;; 19: PUSH ;; 20: LREF(3) ;; 21: CONS_PUSH ;; 22: SHIFTJ(2 2) ;; 23: JUMP -18 ;; 25: RET ;; なし ;; size: 7 ;; 0: GREF_PUSH #<identifier values#user x802ba300>; values ;; 2: CONST_PUSH (1 2 3 4 5) ;; 4: GREF_TAIL_CALL(2) #<identifier map#user x802ba330>; (map values '(1 2 3 4 5)) ;; 6: RETインライン展開されていることが分かる。実際に効果があるか、といわれるとなくは無いがベンチマークレベルで多用しないと目に見えないレベル、の効果だったりする。
これだと高階関数を使用する手続きのインライン展開にしか使えず、定数畳込みはできない。実はもう一段低レベルのマクロがあってdefine-inlinerはそれのラッパーなのだけど、外に見えるようにはしていない。理由は今一APIが気に入らないからだったりする。低レベルのAPIの方が設計が難しい気がしないでもない・・・
No comments:
Post a Comment