Gauche > Archives > 2020/09/13

2020/09/13 14:08:23 UTCtioner
#
「qweは1だけど1はqweとは限らないしaはwerの中の変数だから外でaは変わらないからaを変えてもqweは変わらない」ということでしょうか。
#
(define (wer a b) (set! qwe b))
と関数内で変数に直接代入するしかないのでしょうか。変数、関数、それ(関数)を使って変数に代入する操作、を分けることはできないのでしょうか。
2020/09/13 14:51:30 UTCshiro
#
はい、関数の中に入った時点で、渡されるものはqweの持っていた「値」になっていて、qweとの関係は切れてしまっています。関数の中から何か外に影響を与えたいなら、値を直接渡すのではなく「箱」に入れて渡して、箱の中身を書き換えてもらう、という手はあります。
#
(define qwe (list 1))  ; 「箱」としてペアを使う

(car qwe)  ; => 1  「箱」の中身はcarで取り出せる
     
(define (wer a-cell b)  ; werは箱を受け取ってそのcarを書き換える
  (set-car! a-cell b))

(wer qwe 2)

(car qwe)  ; => 2
2020/09/13 14:58:18 UTCshiro
#
上のようにペアを書き換えて「箱」として使うのはLispのデータ構造にペアと数値とシンボルしか無かった頃からの伝統ですが、現代ではペアは色々な目的に使われるので「箱」ですよ、というのを明示できるデータ型を使うことが多いです。文字通りBoxというのもありますし、parameterというのも多用されます。parameterを使って書くとこんなかんじ:
#
(use gauche.parameter)

(define qwe (make-parameter 1))  ; parameterという「箱」を使う

(qwe)   ;=> 1   parameterから値を取り出すのは単に手続きとして呼び出すだけ

(define (wer a-param b)
  (a-param b))         ; parameterに引数を渡すと中身が書き換えられる

(wer qwe 2)

(qwe)   ;=> 2
#
なお、上のコード例で (set-car! a-cell b) は (set! (car a-cell) b)、(a-param b)は (set! (a-param) b) と書くこともできます。 (set! <なんとか> value) は、次に <なんとか> を評価するとvalueが得られるようになる、と読むことができます。
2020/09/13 16:38:00 UTC齊藤
#
R7RS が parameterize 構文を経由せずにパラメタを書き換えられることを保証していない (パラメタオブジェクトに引数を渡した効果は実装依存) のは、あくまでも動的スコープを模倣する目的で使うためのものだろうという意図が見えるので可能なら box を (またはそれに相当するものを定義して) 使うのが綺麗かなぁと個人的には思います。
2020/09/13 16:44:09 UTCshiro
#
確かに。規格内でやるならboxですね。
#
R7RSで書くとこんな感じ
#
(import (scheme base) (scheme box))

(define qwe (box 1))  ; 1を入れた箱を作る

(unbox qwe)   ;=> 1   値を取り出す

(define (wer a-box b)
  (set-box! a-box b))   ; 箱に値を入れる

(wer qwe 2)

(unbox qwe)   ;=> 2
#
Gaucheなら最初のimportのかわりに(use scheme.box)でもよい
2020/09/13 19:16:43 UTCtioner
#
ありがとうございます。