hiraの疑問とか悩みとか
'()
atmarkをwriteすると|@|となるのですが、なぜでしょう。 SXMLをwriteするときにイヤンな感じなので@のみにして欲しいと思ったのですが、きっと訳ありに違いないと思ったので質問してみました。
;;;実行例 (write-to-string '@) ;=> "|@|" (eq? '@ (read-from-string "@")) ;=> #t ;;;これが#tになって欲しい (let1 atstr "@" (equal? atstr (write-to-string (read-from-string atstr)))) ;=> #f
;;;これが#tになって欲しい (let1 atstr "@" (equal? atstr (write-to-string (read-from-string atstr)))) ;=> #fで、シンボルの正/不正についてですが、R5RS的に不正とはいうものの、Gauche的には正(というかちゃんと読める)というのがこのコードの主張です。
(eq? '@ (read-from-string "@")) ;=> #tまた、read-tableがいじれるようになった場合、シンボルの正/不正という議論は無意味なものになると思います(read-tableをどうするかについては保留のままでしたっけ?)。 結局、人間にとっての見た目を気にする場合はwrite一発では済まず、適当に整形してあげる必要があるのでSXML整形出力関数を書いているのですが、この@を特別扱いするのが面倒なので綺麗で簡単な回避策を探しているというのが現状です。メリットは(read-tableのカスタマイズ機能が無い現状では)@についてしか無い、という意見には賛成です。あと、printはdisplayなので、シンボル・キーワード・文字列などの区別がつかなくなってしまうので、今回の用件では使えません。
(symbol? '123abc) ;=> #t (symbol? '123) ;=> #f (write-to-string '123abc) ;=> "|123abc|" (read-from-string "123abc") ;=> |123abc|(あーん、長文書いてたらconfrictしちゃいました・・・Shiroさん飛び出てるし↓)
acのときの1,2が#fになるのはこういうものなんでしょうか? abと同様、"a","c"が返ることを期待していたのですが、どうでしょう。
((#/(a)(b)|(a)(c)/ "ab") 0) ;=> "ab" ((#/(a)(b)|(a)(c)/ "ab") 1) ;=> "a" ((#/(a)(b)|(a)(c)/ "ab") 2) ;=> "b" ((#/(a)(b)|(a)(c)/ "ac") 0) ;=> "ac" ((#/(a)(b)|(a)(c)/ "ac") 1) ;=> #f ((#/(a)(b)|(a)(c)/ "ac") 2) ;=> #f
いきなり自己解決(ココに書くと速攻で自分のミスに気付くらしい。)↓
((#/(a)(b)|(a)(c)/ "ab") 0) ;=> "ab" ((#/(a)(b)|(a)(c)/ "ab") 1) ;=> "a" ((#/(a)(b)|(a)(c)/ "ab") 2) ;=> "b" ((#/(a)(b)|(a)(c)/ "ab") 3) ;=> #f ((#/(a)(b)|(a)(c)/ "ab") 4) ;=> #f ((#/(a)(b)|(a)(c)/ "ac") 0) ;=> "ac" ((#/(a)(b)|(a)(c)/ "ac") 1) ;=> #f ((#/(a)(b)|(a)(c)/ "ac") 2) ;=> #f ((#/(a)(b)|(a)(c)/ "ac") 3) ;=> "a" ((#/(a)(b)|(a)(c)/ "ac") 4) ;=> "c"
gauche.parameterの実装を眺めていたのですが、tmp1aとtmp2aが不思議でなりません。 展開されたらtmp1a,tmp2aだらけになるように思ってしまいます。 実際はgensymされたように振る舞っているようなのですが、一般的にそういうものなのでしょうか。 このワザは使える!と思ったのですが、裏技だったらどうしようと不安になったので質問してみました。
↓ここでlet変数のgensymを説明している。letの変数部分に来てやっとgensymらしい。テンプレートに現れているがパターン変数でも識別子... でもない識別子は,リテラル識別子として出力に挿入され る。もしリテラル識別子が自由識別子として挿入されるな らば,その場合,その識別子の束縛であって,かつ元々の syntax-rules のインスタンスが現れている箇所を含んでい るようなスコープの束縛が参照される。
もしリテラル識別子が束縛識別子として挿入されるならば,その場合,その識別 子は,自由識別子の不慮の捕獲を防ぐために実質的に改名される。
;;;lib/gauche/parameter.scm (define-syntax %parameterize (syntax-rules () ((_ (param ...) (val ...) (tmp1 ...) (tmp2 ...) () body) (let ((tmp1 val) ... (tmp2 #f) ...) (dynamic-wind (lambda () (set! tmp2 (param tmp1)) ...) (lambda () . body) (lambda () (param tmp2) ...)))) ((_ (param ...) (val ...) (tmp1 ...) (tmp2 ...) ((p v) . more) body) (%parameterize (param ... p) (val ... v) (tmp1 ... tmp1a) (tmp2 ... tmp2a) more body)) ((_ params vals vars other body) (syntax-error "malformed binding list for parameterize" other)) )) ;;;sample (%parameterize () () () () ((a b) (c d)) body) ;hira image => (%parameterize (a) (b) (tmp1a) (tmp2a) ((c d)) body) => (%parameterize (a c) (b d) (tmp1a tmp1a) (tmp2a tmp2a) () body) => (let ((tmp1a b) (tmp1a d) (tmp2a #f) (tmp2a #f)) (dynamic-wind (lambda () (set! tmp2a (a tmp1a)) (set! tmp2a (c tmp1a))) (lambda () body) (lambda () (a tmp2a) (c tmp2a)))) ;actual? tmp1b, tmp2bのように一意なシンボルになる => (%parameterize (a) (b) (tmp1a) (tmp2a) ((c d)) body) => (%parameterize (a c) (b d) (tmp1a tmp1b) (tmp2a tmp2b) () body) => (let ((tmp1a b) (tmp1b d) (tmp2a #f) (tmp2b #f)) (dynamic-wind (lambda () (set! tmp2a (a tmp1a)) (set! tmp2b (c tmp1b))) (lambda () body) (lambda () (a tmp2a) (c tmp2b))))
そのスコープに束縛されているシンボルの値が欲しいです。
(define a 'A) (define b 'B) (define (ab sym) (let ((a 1) (b 2)) (symbol-bound sym))) (ab 'a) => 1 (ab 'b) => 2
これを実現するsymbol-boundはどうやれば作れますか? evalを使ってもトップレベルの環境しか見れないので、やはり無理なのでしょうか。
(define (eval-ab sym) (let ((a 1) (b 2)) (eval sym (interaction-environment)))) (eval-ab 'a) => A (eval-ab 'b) => B
(use gauche.time) (use srfi-1) ;;everyを知らずに作っちゃったmy-every ;;悔しいのでgaucheのeveryと競争してみる (define my-every (case-lambda ((pred ) #t) ((pred val . rest) (and (pred val) (apply my-every pred rest))))) ;;my-everyからcase-lambdaをはずす (define (my-every2 pred . args) (if (null? args) #t (and (pred (car args)) (my-every2 pred (cdr args))))) ;引数をmy-everyに合わせたgaucheのevery(N-ary caseを削除。Fast pathのみ) (define (every pred . lis1) (or (null-list? lis1) (let lp ((head (car lis1)) (tail (cdr lis1))) (if (null-list? tail) (pred head) ; Last PRED app is tail call. (and (pred head) (lp (car tail) (cdr tail))))))) (define charlist (string->list " 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 ")) (time (apply my-every char? charlist)) (time (apply my-every2 char? charlist)) (time (apply every char? charlist)) ;;;結果 gosh> (time (apply my-every char? charlist)) ;(time (apply my-every char? charlist)) ; real 0.063 ; user 0.063 ; sys 0.000 #t gosh> (time (apply my-every2 char? charlist)) ;(time (apply my-every2 char? charlist)) ; real 0.017 ; user 0.015 ; sys 0.000 #t gosh> (time (apply every char? charlist)) ;(time (apply every char? charlist)) ; real 0.000 ; user 0.000 ; sys 0.000 #t
gaucheのevery速いです。 my-every2は、たまにmy-every並に遅いときがあります。 gaucheのeveryはつねに0。これは(一般的に?)applyのコストが高いからなのでしょうか?
eof-objectを保持していたいのですが、*eof*のような定数ってありませんか? 今はこんなことをやって取得しているのですが、どうもしっくりきません。
gosh> (define eof (with-input-from-string "" (lambda () (read)))) eof gosh> (eof-object? eof) #t
eofの取得方法はこれしかないのでしょうか。 この質問の背景にはGaucheRefj:port-for-eachなどの「入力ポートと関係していないreader」を簡単に作りたい、という要求があります。
gosh> (define u1 (print)) u1 gosh> u1 #<undef> gosh> (eq? u1 (newline)) #t
(define undef (if #f #f))
下のマクロはプロシージャの方が良いのですが、マクロの引数マッチが便利なのでマクロにしちゃってます。
(define-syntax /fi (syntax-rules () ((_ (inf opt) thnk ) (apply with-input-from-file inf thnk (apply %add-autoditect (%parse-opt opt 'i)) )) ((_ (inf args ...) thnk ) (apply with-input-from-file inf thnk ( %add-autoditect args ... ) )) ((_ inf thnk ) ( with-input-from-file inf thnk :encoding "*JP" )) ))
これを次のようなプロシージャに変換したいのですが、どうするのが手っ取り早いでしょう。 作ろうかと思ったのですが、有り物があるならそれを使いたいなぁと思いまして。
(define (/fi . args) 引数パターンでディスパッチして、引数をちゃんとバインドする)
(define /fi (case-lambda ;1 (((inf opt) thnk ) (apply with-input-from-file inf thnk (apply %add-autoditect (%parse-opt opt 'i)) )) ;2 (((inf args ...) thnk ) (apply with-input-from-file inf thnk ( %add-autoditect args ... ) )) (( inf thnk ) ( with-input-from-file inf thnk :encoding "*JP" )) ))