<style> /* basic design */ .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p { font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic'; text-align: left; line-height: 1.6; letter-spacing: normal; text-shadow: none; word-wrap: break-word; color: #444; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;} .reveal h1, .reveal h2, .reveal h3 {color: #00a474;} .reveal th {background: #DDD;} .reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;} .reveal blockquote {width: 90%; padding: 0.5vw 2.0vw;} .reveal table {margin: 1.0vw auto;} .reveal code {line-height: 1.2;} .reveal p, .reveal li {padding: 0vw; margin: 0vw;} .reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #e4ffe5; border-radius: 1.5vw;} /* table design */ .reveal table {background: #f5f5f5;} .reveal th {background: #444; color: #fff;} .reveal td {position: relative; transition: all 300ms;} .reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;} .reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;} /* blockquote design */ .reveal blockquote { width: 90%; padding: 0.5vw 0 0.2vw 6.0vw; font-style: italic; background: #ddffff; } .reveal blockquote:before{ position: absolute; top: 0.1vw; left: 1vw; content: "\f10d"; font-family: FontAwesome; color: #00a474; font-size: 1.6vw; } /* font size */ .reveal h1 {font-size: 5.0vw;} .reveal h2 {font-size: 4.0vw;} .reveal h3 {font-size: 2.8vw;} .reveal h4 {font-size: 2.6vw;} .reveal h5 {font-size: 2.4vw;} .reveal h6 {font-size: 2.2vw;} .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;} .reveal code {font-size: 1.6vw;} /* new color */ .red {color: #EE6557;} .blue {color: #16A6B6;} /* split slide */ #right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;} #left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;} </style> <style> /* 背景デザイン */ .reveal { background-color:/*背景色*/ #f8f8ff; } .reveal h1 {padding: 3.0vw 0vw;} @media screen and (max-width: 1024px) { .reveal h2 {margin: -2.0vw 0 0 0; padding: 0.0vw 0vw 3.0vw 2.0vw; } } @media screen and (min-width: 1025px) and (max-width: 1920px) { .reveal h2 {margin: -1.5vw 0 0 0; padding: 0.0vw 0vw 3.0vw 2.0vw; } } @media screen and (min-width: 1921px) and (max-width: 100000px) { .reveal h2 {margin: -1.0vw 0 0 0; padding: 0.0vw 0vw 3.0vw 2.0vw; } } </style> <style> /* specific design */ .reveal h2 { padding: 0 1.5vw; margin: 0.0vw 0 2.0vw -2.0vw; border-left: solid 1.2vw #00a474; border-bottom: solid 0.8vw #9e9e9e; } </style> <!-- --------------------------------------------------------------------------------------- --> #### 卒業研究 <br> # sintax-parseの効率化 <br> <br> #### 2021/12/10~ ### @ariken --- [TOC] * [datum->syntax](/z3PdlUX3Q8CfTzGvzJcKfg?view#datum-gtsyntax) ## 完成形目標 ```Racket (syntax-parse stx [(foo x) #:do [(define result (if (syntax-property #'x 'class) (if (x のプロパティが myid である);キャッシュ 'success1, #f) (if (x がクラス myid を持っている);実際 'success2, #f)))] #:when result (cond ((eq? result 'success1) パターンマッチ) ((eq? result 'success2) 'myid を付与後にパターンマッチ)) ] [(foo y) #''y]) ``` 5行目〜6行目追加 ```racket (syntax-parse stx [(foo x) #:do [(define result (if (syntax-property #'x 'class) (if (symbol=? (syntax-property #'x 'class) 'myid) 'success1 #f) ;x のプロパティが myid である (if (x がクラス myid を持っている) 'success2, #f)))]; ;ifではなく、(define-syntax (bar stx) ;(syntax-parse stx ;[(_ x:myid) ;#:with y:myid #’x ;#’’y])) ;このように書いてエラーを抽出して、 ;エラーをキャッチして、success2を返すように動かす。 #:when result (cond ((eq? result 'success1) パターンマッチ) ((eq? result 'success2) 'myid を付与後パターンマッチ)) ] [(foo y) #''y]) ``` とりあえず実行できるか確認 ```racket (define-syntax (foo stx) (syntax-parse stx [(foo x) #:do [(define result (if (syntax-property #'x 'class) (if (symbol=? (syntax-property #'x 'class) 'myid) 'success1 #f) #f))] #:when result (cond ((eq? result 'success1) 12) ((eq? result 'success2) 34)) ] [(foo y) #''y])) ``` ``` > symbol=?: reference to an unbound identifier at phase: 1; the transformer environment context...: matching binding...: common scopes...: in: symbol=? ``` 8~9行目の `(symbol=? (syntax-property #'x 'class) 'myid)` のコードで`#f`と`'myid`でbooleanとsymbolで比較しているのが原因。 ###### tags: booleanとsymbol比較 1. `#f`をsymbol型に変換する 2. `symbol=?`とは別の実装方法を考える 1の方法で改善するためのメモ ```racket > (define stx #'x) > (symbol=? (syntax-property stx 'class) 'myid) . . symbol=?: contract violation expected: symbol? given: #f argument position: 1st other arguments...: > (syntax-property stx 'class) #f > (define stx-s (syntax-property stx 'class 'myid)) > (syntax-property stx 'class) #f > (syntax-property stx-s 'class) 'myid > (symbol=? (syntax-property stx-s 'class) 'myid) #t ``` `#t`のときはうまく動作 `#f`のときはエラー ```racket (symbol=? (if (boolean=? (syntax-property stx 'class) ;#f #f) 'ok ((syntax-property stx 'class)) ) 'myid) ``` ```racket > (symbol=? (if (boolean=? (syntax-property stx 'class) #f) 'ok ((syntax-property stx 'class))) 'myid) #f > (symbol=? (if (boolean=? (syntax-property stx-s 'class) #f) 'ok ((syntax-property stx 'class))) 'myid) . . boolean=?: contract violation expected: boolean? given: 'myid argument position: 1st other arguments...: ``` 今度はstxが`#f`のときはうまく動作するが、`symbol`のときはエラー... `(boolean=? (syntax-property stx-s 'class) #f)` が`symbol`と`boolean`の比較をしているから。振り出しに戻った... ###### tag [booleanとsymbol比較](#tags-boolean%E3%81%A8symbol%E6%AF%94%E8%BC%83) * ### `eq?`で解決しました........😭 ```racket (define-syntax (foo stx) (syntax-parse stx [(foo x) #:do [(define result (if (syntax-property #'x 'class) (if (eq? (syntax-property #'x 'class) 'myid) 'success1 #f) ;x のプロパティが myid である #f))] #:when result (cond ((eq? result 'success1) 12) ((eq? result 'success2) 34)) ] [(foo y) #''y])) ``` ```racket #lang racket (require syntax/parse) (require syntax/parse/debug) (require (for-syntax syntax/parse)) (define-syntax (foo stx) (define-syntax-class myid #:description "myid" (pattern (x:myid)) (pattern (x:id)) (pattern (x:number)) (pattern (x:keyword))) (syntax-parse stx [(_ x) #:do [(define result (if (eq? (syntax-property #'x 'class) 'myid) ;条件 'success1 ;x のプロパティが myid である (#t) (syntax-parse #'x ;x のプロパティが myid でない (#f) [x ;ため、x のクラスが myid か確認する #:with y #'x #:declare y id 'success2])))] ;x のクラスが myid である (#f) #:when result (cond ((eq? result 'success1) (println 'ok1)) ((eq? result 'success2) (println 'ok2))) ] [(_ y) #'y])) ``` --- ## 研究本文 ![](https://i.imgur.com/CTgYU7L.jpg) ![](https://i.imgur.com/Pd0i0eU.jpg) ![](https://i.imgur.com/DYr7woA.jpg) --- ## 進捗管理 > [time=Fri, Jan 21, 2022 10:00 AM] ::: info 目標:現在実装中の`fast-syntax-parse`が完成すること。 完成後に性能評価もできれば◎ ::: * 現時点のプログラム ```Racket= #lang racket (require syntax/parse) (require syntax/parse/debug) (require (for-syntax syntax/parse)) (define-syntax (fast-syntax-parse stx) (syntax-parse stx [(_ target [pattern body]) #'(syntax-parse target [(_ x);なんとか:myidを取り除く、かつ名前をつけて覚えておく ;(string-contains? x ":myid") #:do [(define result (if (eq? (syntax-property #'x 'class) 'myid) 'success1 (syntax-parse #'x [x #:declare x myid 'success2])))] #:when result (cond ((eq? result 'success1) #'(body)) ((eq? result 'success2) (with-syntax ([x2 #'(syntax-property #'x 'class 'myid)]) ;'myidを付与 #'(new_body);x2 を渡した new_body ))) ]) ])) ``` ---- ## 改善箇所 * 11行目の:myidを取り除き、名前をつけて記録するところ * 26~27行目の'myidを付与した後にbodyを実行する部分 ### 改善方法 1. 11行目,xはstringではなく構文オブジェクトなのでstring-contains?をそのように呼び出すことはできないですね. 識別子(シンボルがsyntax-eであるような構文オブジェクト)を受け取り,そのシンボルの文字列表現中に文字「:」があるなら「:」以降の文字列をシンボルにしたものを返す,「:」がなければ#fを返す,という関数をまず定義してみてはどうでしょうか? 2. 26行目,27行目の方は,bodyの中のxをx2に全部置き換える必要があるので, (define (substitute body old-id new-id) …) という関数を定義してはどうでしょう? bodyは任意のリストがsyntax-eであるような構文オブジェクト old-id と new-id はシンボルがsyntax-eであるような構文オブジェクト(つまり識別子) たとえば,body が #’(+ x y) のとき,(substitute body #’x #‘x2) と呼び出せば,#’(+ x2 y) を返す関数です. ---- ### 改善 1. ```racket= (define (colon-exist? target) (if (string-contains? (syntax->datum target) ;3行目でlist->stringを使って文字列化したい ;例(list->string (list #\A #\p #\p #\l #\e)) -> "Apple" ":");この時に「:」が何文字目にあるかを記憶しておく(n) ;#tのとき、「:」以降の文字列をシンボルにしたものを返す ;(substring "Apple" 1) -> "pple"が役立ちそう ;#f)) ``` ```racket (define (colon-exist? target) (if (string-contains? target ":") (substring target 1) #f)) ``` ```racket (define (colon-exist? target) (if (string-contains? (expr->string target) ":") (substring (expr->string target) 2) #f)) (define X #'(define y:myid 5)) (map (lambda (ex) (colon-exist? ex)) (syntax->datum X)) '(#f "myid" #f) ``` ```racket (define (colon-srch str n) (if (string-prefix? str ":") n (colon-srch (substring str 1) (+ n 1)))) ;(colon-srch b 1) -> 2 ;"y:myid"の中から「:」が何文字目に存在するか? (define (colon-tail-cut target) (if (string-contains? (expr->string target) ":") (string->symbol (substring (expr->string target) (colon-srch (expr->string target) 1))) #f)) ``` 2. ```racket (define (substitute body old-id new-id) (if (member old-id (syntax->datum body)) #t(old-idをnew-idに書き換える) ;無理そうならnew-bodyを新しく定義する #f(なかったら特に何もしない))) ``` ```racket (define a #'(+ x y)) (map (lambda (ex) (if (eq? ex 'x) 'x2 ex)) (syntax->datum a)) '(+ x2 y) (define (substitute body old-id new-id) (map (lambda (ex) (if (eq? ex (syntax->datum old-id)) (syntax->datum new-id) ex)) (syntax->datum body))) ``` --- ## 完成(仮) ```racket= #lang racket (require syntax/parse) (require syntax/parse/debug) (require mzlib/string) ; expr->string に必要 (require (for-syntax syntax/parse)) ; (colon-srch "y:myid" 1) -> 2 ; "y:myid" の中から 「:」 が何文字目に存在するか? (define (colon-srch str n) (if (string-prefix? str ":") n (colon-srch (substring str 1) (+ n 1)))) ; (colon-tail-cut 'average:number) -> 'number' ; (colon-tail-cut 'fast-syntax-parse) -> #f ; この関数に渡したときに 「:」 が存在すれば後ろの部分をカットして symbol 型で返す. (define (colon-tail-cut target) (if (string-contains? (expr->string target) ":") (string->symbol (substring (expr->string target) (colon-srch (expr->string target) 1))) #f)) ; body が #’(+ x y) のとき, ; (substitute body #’x #‘x2) と呼び出せば, ; #’(+ x2 y) を返す関数 (define (substitute body old-id new-id) (map (lambda (ex) (if (eq? ex (syntax->datum old-id)) (syntax->datum new-id) ex)) (syntax->datum body))) (define-syntax (fast-syntax-parse stx) (syntax-parse stx [(_ target [pattern body]) #'(syntax-parse target [(_ x) #:do [(define myid (car (filter symbol? (map (lambda (ex) (colon-tail-cut ex)) (syntax->datum x))))) (define result (if (eq? (syntax-property #'x 'class) myid) 'success1 (syntax-parse #'x [x #:declare x myid 'success2])))] #:when result (cond ((eq? result 'success1) body) ((eq? result 'success2) (with-syntax ([x2 #'(syntax-property #'x 'class myid)]) ;'myidを付与 (datum->syntax #'lex (substitute body #'x #'x2); new_body #'srcloc)))) ]) ])) ``` --- ## syntax-property ```racket (syntax-property stx key v [preserved?]) → syntax? stx : syntax? key : (if preserved? (and/c symbol? symbol-interned?) any/c) v : any/c preserved? : any/c = (eq? key 'paren-shape) (syntax-property stx key) → any stx : syntax? key : any/c ``` 3 つまたは 4 つの引数を持つ形式は、任意のプロパティ値 v をキー key に関連付けることで stx を拡張します。その結果、関連付けされた新しいシンタックス オブジェクトが生成されます (stx 自体は変更されません)。プロパティは preserved? が真の場合は preserved として追加されます。この場合、key はインターネッドされたシンボルでなければならず、v はマーシャルされたバイトコードに保存できる後述の値でなければなりません。 2つの引数を持つ形式は、stxにkeyに関連付けられた任意のプロパティ値を返し、keyに関連付けられた値がstxにない場合は#fを返します。stx が汚染されている場合は、結果の値を持つシンタックス オブジェクトも汚染されています。 バイトコードへのマーシャリングをサポートするために、保存された構文プロパティの値は、次のいずれかの非循環値でなければなりません。 * 許可された保存されたプロパティの値を含むペア。 * 許可された保存されたプロパティ値を含むベクトル(不変的にマーシャルされていない)。 * 許可された保存されたプロパティ値を含むボックス(unmarshaled as immutable)。 * 許可された保存されたプロパティの値を含む不変のプレハブ構造 * 許可されたプリザーブドプロパティ値を持つキーと値を持つ不変のハッシュテーブル * シンタックスオブジェクト、または * 空のリスト、記号、数値、文字、文字列、バイト文字列、または正規表現のいずれかの値。 保存されたプロパティに他の値があると、所有するシンタックスオブジェクトをバイトコード形式にマーシャリングしようとしたときに例外が発生します。 ## メモ ```racket (define stx #'x) (define stx2 (syntax-property stx 'class 123)) (syntax-property stx2 'class) 123 ``` ```racket > (syntax-property stx 'class) #f > (syntax-property stx2 'class) 123 > (syntax-property stx2 'myid 234) .#<syntax:3-unsaved-editor:14:14 x> > (syntax-property stx2 'myid) #f > (syntax-property stx2 'class 234) .#<syntax:3-unsaved-editor:14:14 x> > (syntax-property stx2 'class) 123 > (define stx3 (syntax-property stx2 'class2 234)) > (syntax-property stx3 'class) 123 > (syntax-property stx3 'class2) 234 > (syntax-property stx2 'class) 123 > (syntax-property stx2 'class2) #f > (syntax-property stx2 'class2 345) .#<syntax:3-unsaved-editor:14:14 x> > (define stx2 (syntax-property stx2 'class2 345)) define-values: assignment disallowed; cannot re-define a constant constant: stx2 in module:'anonymous-module (if (= (syntax-property stx2 'class) 123) (display "OK") (display "NG")) OK > (syntax-property stx 'class) #f > (syntax-property stx2 'class) 123 > (define stx-myid (syntax-property stx 'class 'myid)) > (syntax-property stx-myid 'class) 'myid > (if (symbol=? (syntax-property stx-myid 'class) 'myid) 'success #f) 'success > (syntax-parse #'(1 2 3) [(a b c) #:with rev #'(c b a) #'rev]) #<syntax:eval:15:0 (3 2 1)> ``` ---
{"metaMigratedAt":"2023-06-16T16:02:53.987Z","metaMigratedFrom":"YAML","title":"研究","breaks":true,"slideOptions":"{\"theme\":\"white\",\"controls\":true,\"progress\":true,\"slideNumber\":\"c/t\",\"center\":false,\"fragments\":true,\"help\":true,\"transition\":\"convex\",\"transitionSpeed\":\"default\",\"keyboard\":true,\"width\":\"93%\",\"height\":\"100%\",\"previewLinks\":false,\"spotlight\":{\"enabled\":false}}","contributors":"[{\"id\":\"a0de3d6a-cf71-4961-a3bb-e324e7c21a77\",\"add\":23797,\"del\":11474}]"}
    286 views
   Owned this note