#こんばんは
#flonumの修正ありがとうございます>shiroさん
#皆さんに質問
#(define (baz n)
(let loop ((i 0) (res '(A)))
(if (= i n) (reverse! res)
(loop (+ i 1) (cons i res)))))
#のreverse!が'(A)を破壊して、2回目の呼び出し以降、意図しない結果が(試してみたどの処理系でも)返ってきますが、
#こういうのって感覚的に当然避けるべきコードでしょうかね
##↑上のエントリのコメント欄に通りすがりさんが書いて下さっているように、'(A) の代わりに (list 'A) などその場でコンシングするように書けば大丈夫です
#「感覚的に避けるべき」というより、そもそも不正なコードです。
#Cでこう書くのと同じようなことです。
#void foo()
{
char *z = "abcde";
z[0] = 'A';
}
#処理系によっては、実行時にSEGVするものもあれば、実行時に黙ってデータを書き換えちゃうものもあるでしょうが、C言語的には「書いてはいけないコード」ですね。
#リテラルの破壊的変更も、それをやった時点でScheme的には未定義な状態になります。何が起きてもおかしくはない。
#もちろん警告を出したりエラーにしたりするのが親切なんでしょうが、Gaucheのような動的コンパイル処理系でコンスセルのimmutabilityをチェックするのはオーバヘッドになるので…
#どうもありがとうございます。>そもそも不正なコード
#感覚的にというと語弊があったかと思いますが、shiroさんのC言語の例のようなコードが駄目なのが身体に叩き込まれているのと同様に、schemeでの不正コードが不正であることがぱっと見抜けるかどうか(昨日の自分は変な結果を見るまで気づかなかった)という
#ああ、感覚的というのはそういうことでしたか。
#私は確かにリテラルが変更されてるコードには身体が反応しますね :-)
#でも、リテラル変更問題はone of the most FAQなので、できれば処理系側で検出してやりたいんですがねえ。
#リテラルを特定のメモリページに割り付けて、割り当てが済んだらページ属性をread onlyにしちゃう、とかすれば、変更しようとするとSEGVるので検出はできます。ただポータブルにできるかなあ、というのと、そのページ用にgcを書いてやらなければならないというのが大変。
#あるオブジェクトがリテラルかどうかをschemeのコード側から知る方法があれば対策が打てるかな
#コストがかかってもいいから、ということ?
#はい、デバッグ時だけですが
#とか言ってるとデバッグ用のgoshと本番用のgoshを使い分けることになるのか
#↑自分が今回と同じパターンでつまづく事はあまりないと思うのですが、ソースからリテラル変更箇所の有無を検出する方法があればと
#ふーむ。リテラルのコンスセルを全部extended pairにしちゃう、とかすれば通常アクセス時のオーバヘッドは無くて済むかなあ。read時の負担がどのくらいあるか…
#なるほど>extended pair
#'(a) とかくかわりに `(a) と書けば大丈夫だったりします?
#いえ、中身が定数だとオプティマイザが定数リストに置き換えちゃいます。
#あーだめですか。じゃあ (list 'a) とするしかないですか。
#破壊的な操作って、普段あんまりやらないから、たまにやるとはまるっていう感じですかね。
#継続と破壊的操作のコンボバグはかなり厄介です。
#なるべく末端のモジュールは純粋関数的に書いとくのが吉でしょうね。