Slide 1

Slide 1 text

Scheme用Linterの改良 (マクロ逆展開を可能なかぎりやる?) Niyarin

Slide 2

Slide 2 text

Scheme用Linter、Red-parenについて ○パターン列挙型のLinter Red-paren (apply append (map some-proc (foo x))) ソースコード ((apply append (map f ls …)) (append-map f ls …)) … 略) パターン(rules+) (append-map some-proc (foo x)) と書けるよ niyarin/red-paren

Slide 3

Slide 3 text

Red-parenのちょっとした問題 ○マクロに対して弱い 例) threading macro (ネストした式を平らにする) (->> some-list (filter (λ (x) (not (some-pred? x))) ) … ) (->> some-list (remove some-pred?) …) と動いてほしい (filter (lambda (x) (not (pred x))) ls) このマクロを使うとremoveのルールにマッチしない removeのルール

Slide 4

Slide 4 text

マクロが問題になるケースは多いのか? 普通のマクロは問題ない ○ 問題の原因の多くは手続き適用を壊すマクロ ・ threading macro ・ condp ○レアケースと思って良さそう(たぶん) ※これらが悪だとは言っていない(私はcondpが好きです)

Slide 5

Slide 5 text

マクロ展開→ Lint適用 (->> some-list (filter (λ (x) (not (some-pred? x)))) なにか1 なにか2 なにか3) (なにか3 (なにか2 (なにか1 (remove some-pred some-list)))) マクロ展開+Lint ○ マクロを使うとすり抜けるのでマクロ展開してからLintを書けてみる ☓ これは求めていたものとは違う(ちょっと不親切)

Slide 6

Slide 6 text

マクロを逆展開する機構が欲しい (->> some-list (remove some-pred) なにか1 なにか2 なにか3) (なにか3 (なにか2 (なにか1 (remove some-pred some-list)))) ○ マクロを逆展開する操作があれば理想的な指摘コードが得られる マクロ逆展開 前ページの例の続き

Slide 7

Slide 7 text

syntax-rulesって逆にしても使え”そう” Schemeの標準(R7RS)のマクロシステム ○ let → lambdaの例 lambda → let も逆からマッチさせることでできそう (syntax-rules () ((let ((name val) ...) body1 body2 ...) ((lambda (name ...) body1 body2 ...) val ...)))

Slide 8

Slide 8 text

syntax-rulesって逆にしても使え”そう” そう簡単にはいかない (1) ruleに同じ変数を含んではいけない → これは同じ変数が同じものにマッチしているならよいことにする (2) 2回以上のellipsis → backtrack+最短マッチで妥協する? (3) ruleだけに存在する変数や_ → あきらめる(ほとんどないケースだと思う) (4) ruleは上からマッチする仕様だが、逆は必ずしもそうではない → 次のページ (5) hygenic性とか先頭がsymbolでないことも目をつぶる

Slide 9

Slide 9 text

復元できそうなものを全列挙する (->> (a b) c) (->> (->> (a b) c)) (->> b a c) (->> b (a) c) 決定的に出せないので全列挙 → どれか1つが理想的なもの

Slide 10

Slide 10 text

逆展開例 (->> なにか1なにか2 (なにか3 なにか4) (filter (lambda (x) (not (some-pred? x)))) なにか5) (->> なにか1 なにか2 (なにか3 なにか4) (remove some-pred?) なにか5) (->> なにか5 (->> (remove some-pred? (なにか3 なにか4 (なにか2 なにか1))))) (->> なにか1 (なにか2) (なにか3 なにか4) (remove some-pred?) なにか5) 理想 不自然なコード(正しく動作はする) 理想と近いが正しく動作しない 元のコード

Slide 11

Slide 11 text

どのように理想的なコードを見つけるのか 適当な評価式を与えて最もポイントが高いのを選択する ○ (同じ要素が同じ順序で含む数 , - 最大の深さ , - 式の長さ ) ・一応、threadingマクロ例の理想コードはこれでとれはする 理想:(5 -2 -6) 不自然なコード:(1 -5 -3) 動作しないコード:(4 -2 -6) ・てきとうなので改良はいる

Slide 12

Slide 12 text

sexp-diffとかもよいかもしれない ・Racket系のs式diff #:newと#:oldを付けて差分が分かる > (sexp-diff '(->> some1 some2 (some3 some4) (filter (lambda (x) (not (some-pred? x)))) some5) '(->> some1 some2 (some3 some4) (remove some-pred?) some5)) '((->> some1 some2 (some3 some4) #:new (remove some-pred?) #:old (filter (lambda (x) (not (some-pred? x)))) some5))

Slide 13

Slide 13 text

Red-parenに組み込む ・マクロ情報をユーザが渡さないと使えない → 名前空間からマクロを得る部分が必要 というわけで組み込むのはまだ先 ・マクロ逆展開は実装済み ・信頼性は落ちるのでなんらかのタグをつける

Slide 14

Slide 14 text

おわり