Gauche > Archives > 2009/08/14

2009/08/14 02:17:05 UTChigepon
#
なるほど。コピーバックしています。たしかにヒープに置いたままできますね。
#
自分も捕捉は軽くを目指したいなと思って見ているんですが、restore 用のインストラクションを捕捉時に on the fly で生成していたりと無駄が多いです。
#
Chez はどうやっているか知らないんですが、start, end だけ覚えて copy on write とかでしょうか?
#
作りかけの引数の件はやっと謎が解けました。そういうことだったのか。Reading Gauche のときにずっと気になっていた。
2009/08/14 02:27:16 UTChigepon
#
>The technique employs a form of lazy stack copying, i.e., call/cc becomes a constant-time allocation operation, and returns to captured continuations copy the existing stack only as far as needed.
#
おお。正解だった。
#
VM のスタック push 操作時に lazy stack copying check が入るというオーバーヘッドがありそうだけど、どうやって
#
解決しているんだろう。
2009/08/14 02:33:09 UTChigepon
#
捕捉を軽くできると、(心理的に)気軽に guard を使えるようになりますね。
2009/08/14 04:16:10 UTCPocket
#
質問です、
#
二つのlistの同じ位置にある要素を交換する関数を書きたいのですが、
#
新たにコンスする事なく破壊的動作で実現する事が出来るでしょうか?
#
破壊的動作にしたいのは、この関数を再帰でかなりの回数繰り返す事に使いそうなので
#
メモリを食いつぶしてほしくないからです。
2009/08/14 05:01:09 UTChigepon
#
'(A B C D) と '(a b c d) があって C と c を交換したい
#
みたいな話ですか?
#
もしそうなら
#
(import (rnrs)
        (rnrs mutable-pairs))

(define (swap-nth! lst1 lst2 n)
  (define (ref lst n)
    (let loop ([i 0]
               [lst lst])
      (if (= i n)
          lst
          (loop (+ i 1) (cdr lst)))))
  (let* ([p1 (ref lst1 n)]
         [p2 (ref lst2 n)]
         [tmp (car p1)])
    (set-car! p1 (car p2))
    (set-car! p2 tmp)))

(let ([lst1 '(a b c d)] ;; リストリテラルを破壊するのは行儀が悪いよ
      [lst2 '(A B C D)])
  (swap-nth! lst1 lst2 2)
  (display lst1)
  (newline)
  (display lst2))
#
(a b C d)
(A B c D)となります。リストの長さとかチェックしていませんが。
#
srfi-1 あたりに n 番目の pair を返すのないんだっけか。
2009/08/14 05:40:46 UTChigepon
#
call/cc の呼び出しが遅い原因は、ほぼヒープアロケーションだった。
#
(define a '())
(let loop ([i 0])
  (cond
   [(= i 100000) '()]
   [else
    (call/cc (lambda (c) (set! a 3)c))
    (loop (+ i 1))]))
#
のような単純なものでも、stack 要素を 80 個ほど分のメモリを割り当てしていてそこが遅い。
#
ちなみに見た目よりもスタックが深いのは R6RS に使っている psyntax が外側にあるため。
#
>VM のスタック push 操作時
#
は間違い。スタックが失われるとき。
#
論文発見:継続の生成におけるスタックコピーの遅延
2009/08/14 06:00:10 UTCPocket
#
higeponさんありがとう御座います!
2009/08/14 06:03:40 UTChigepon
#
交換したい要素までリストをたどって set-car! するという感じです。
2009/08/14 06:15:13 UTCPocket
#
なるほど、そのようにすれば良いのですね、
#
今ルービックキューブをCUIで再現できないかと考えているのですが、
#
回転動作を再現するときに面の色を入れ替えるのをどのようにすれば良いかかんが手居た所でした。
#
s/かんが手居た/考えていた/
2009/08/14 06:20:17 UTChigepon
#
ルービックキューブなら、リストの長さがあらかじめ決まっていると思うので、リストではなくて vector にすれば swap や回転が簡単になるかもしれませんね。
2009/08/14 06:48:06 UTCとおる。
#
(define (swap-cdr! l1 l2)
  (let1 l1-cdr (cdr l1)
    (set-cdr! l1 (cdr l2))
    (set-cdr! l2 l1-cdr)))

(define (swap-nth! l1 l2 n)
  (unless (< n 0)
    (when (< n 2)
      (swap-cdr! l1 l2))
    (swap-nth! (cdr l1) (cdr l2) (- n 1))))
#
set-cdr! を使ってみました。値のコピーが発生しないので経済的かも。
2009/08/14 06:49:22 UTC齊藤
#
そういえばルービックキューブってどんな状態からでも最大24手で揃えられるって証明されてましたね
#
サイズが大きいものだともっと増えるんでしょうが、必勝法ってあるのかな
2009/08/14 06:51:05 UTCとおる。
#
ルービックキューブいまだに 1 面しかそろえられません。
#
やり方を人に聞いたので、買って試してみたいんですが、なぜかおもちゃ屋さんには 5x5x5 とかすごいのしかうってません :D
2009/08/14 14:56:44 UTCshiro
#
ジェネリックファンクションディスパッチの速度が気にならないなら、(use gauche.sequence) しとくと普通にset!でリストの途中を置き換えられますよ。
#
gosh> (use gauche.sequence)
#<undef>
gosh> (define x (list 'a 'b 'c 'd 'e))
x
gosh> (set! (ref x 2) 'A)
#<undef>
gosh> x
(a b A d e)
#
@higepon chezのcall/ccについてはdybvigさんの論文がいくつかあったような
2009/08/14 15:06:32 UTCshiro
#
基本的な考え方としては、継続を捕まえた時点で、その時のspの位置を新たな「スタックの底」とみなすって考えです。スタックが短くなる。
#
で、それをやってるとどんどんスタック領域が減ってくので、適当なタイミングでスタック領域をGCすると、その時点で生きている(「スタックの底」より下に沈んでしまった)アクティベーションフレームはGCによってヒープに移されて、スタックはまた広くなると。
#
これだと、guardみたいな上方への脱出のみに使われる継続は、スタックGCがかかる前にその領域を抜けてしまえばすぐゴミになるので、ヒープへのコピーをせずに済みます。
#
実装上の問題は、捕まえた継続が保持しているアクティベーションフレームへのポインタがGCによって書き換えられる可能性があることで、これはprecise copying gcを使ってる処理系では全然構わないんですが、conservative gcだとポインタを書き換えて良いのかどうかの判断がGCに出来ないので難しいってことです。
2009/08/14 17:00:47 UTCayato
#
kahuaについて質問です。
#
高階タグ関数にhtmlタグを含む文字列を渡すと、<,>,&,",'が勝手にエスケープされてしまうので、server.scm中の973行目を
#
(define sxml:string->xml-bis
  (make-char-quotator
   '((#\< . "&lt;") (#\> . "&gt;") (#\& . "&amp;") 
     (#\" . "&quot;") (#\' . "&#39;"))))
#
から
#
(define sxml:string->xml-bis
  (make-char-quotator
   '()))
#
に書き換えたら期待する動作が得られたのですが、kahuaの動作自体は問題ないですよね?
2009/08/14 17:17:37 UTCshiro
#
kahuaのコアは問題ないはずですが、マクロなどでエスケープされることを前提にしてるものがあるかもしれません。
#
意図としては、高階タグ関数の入力は「生の文字列」、レンダリング結果が「htmlマークアップされた文字列」ということで、意味的な型が違うと考えられます。
#
したがって「htmlマークアップされた文字列」を高階タグ関数に渡すのは意味的にドメインエラーではあるんですね。
#
どうしてもマークアップ済み文字列を渡したければ、(noescape/ ...) みたいな関数を作ってそこに閉じ込める方がいいと思います。
#
(それもあくまで緊急避難措置であって、設計上は「生の文字列」と「マークアップ済み文字列」は混ぜるべきじゃないかと。)
#
エンティティ参照を入れたいっていう話は昔あって、専用の関数が書かれた記憶があるけど、kahua本体に入ってたっけな。
2009/08/14 17:55:07 UTCayato
#
回答ありがとうございます。生の文字列だけで済むように試行錯誤してみます。
2009/08/14 22:01:03 UTCえんどう
#
実体参照は&/と&:で書けます。($/ "nbsp")とか。
#
訂正: (&/ "nbsp")