Gauche:スロットアクセス
hiraさんのとこより:
2004/03/02 07:42:32 PST: slotにprivateなアクセッサを定義しようとして、あれ?っと思いました。 generic functionでディスパッチということは、自他の区別なんて無いのかと。 moduleのimport/exportが近いけど、staticな変数の可視/不可視の制御なので、ちょっと違う。 slotにpublic/privateの概念を持ち込むにはどうすればいいのだろう? クラスの中に入る仕組みがあれば良いのだろうけど。 そうすれば、slot-refにイライラしなくても済むっていうオマケも付くのだが。
(slot-ref self 'hoge) ;;21文字 CLOS:フツーの書き方 this.getHoge() //14文字 Java:thisマニアが自己カプセル化したときの書き方 hoge ;; 4文字 CLOS/Java:私が望む書き方
- スロット参照構文
- 可視性の制御
- 番外編:Message Passing Style (MPS)について
- symbolをapplicableにする
- 空気を読んでsymbolをlambdaにする
- applyよりも柔軟なapplyを定義する
- symbolとobjectの列が交互にあらわれるシーケンスをつかった参照構文
- 参照の分配(~の意味上の反転)
- (~ symbol1 symbol2 )の解釈
スロット参照構文
Shiro: 私もslot-refにはうんざりしてます。最近はほとんど (ref self 'hoge)ですが、それでも面倒です。
with-slot
スロット名だけ、っていうのは、CLOSだとwith-slots構文が ありますね。Gaucheでも参照に関してはマクロですぐ書けますが、 (set! hoge value)を実現するのは難しそうです。
(with-slots (hoge huge hage) object ... hoge ...) ;; <- この中でのhogeはobject.hogeを参照
いくつかのScheme処理系には、識別子自体をマクロフォームとして 展開できるものがあり(例: SchemeCrossReference:define-id-macro)、 そういうのを使ってwith-slots内のhogeを(ref object 'hoge)に 展開してしまえば、set!も使えます。
ただ、わたし自身は「レキシカルスコープだけ」という単純さが Schemeの強さだと思っているので、複数のスコープルールを持ち込むのは 話をややこしくするだけだと思います。例えば:
(with-slots (hoge fuge hage) object (lambda () hoge))
こんなふうにクロージャを作った場合、クロージャ内のhogeは 何をクローズしているでしょうか?
Scheme的に考えれば、この時点でレキシカルなobjectに束縛された オブジェクトのhogeスロット、ですね。 ただ、インスタンス変数にselfやthis無しで アクセスできるようなOOPの場合、暗黙のスコープとして 「その時問題になっているインスタンス」が仮定されるので、 クロージャ作成時のobjectではなく、 クロージャ実行時のobjectを参照したくなる場合もあるんじゃないでしょうか。 (そもそもクロージャなんてない、ってOOPでは、作成時のobjectを 閉じ込むっていうこと自体できませんし)。
- こ、これはどういう事なんだろう?イメージ出来ない。。。例題下さい。hira(2004/03/03 02:31:57 PST)
[x y]
'ref'は特に、オブジェクトのスロットの先のオブジェクトのスロットの… とたどってゆくときにうざくなります。
(ref (ref foo 'bar) 'baz)
今、ぼんやりと、これをこんな風に書けたらどうかなあと思っています。
[foo 'bar 'baz]
メカニズムとしてはリーダーマクロでrefのネストに展開します。 これだと、普通のスロットアクセスは [this'hoge] とか (set! [this'hoge] value) になります。どんなもんでしょ。
ちなみに、[x y]を(ref x y)に展開する、とだけ定めておくと、 自動的にこういうこともできます。
(define x '#(a b c)) [x 1] => b ;; vector-ref (define x "abc") [x 2] => #\c ;; string-ref
- 単純なルールで色々実現されてしまう、というのはいいですねぇ。--hira
暗黙のself
- おお、だいぶ短くなりましたね。[]←これ、「スロット」っていう感じ出してるし:-)
カッコをのぞけばカプセル化しないthisマニアと互角か。やっぱ、self/thisは取り除けないっすよねー。define-methodに手を入れて、selfを予約語にして、不健全なマクロで参照っていうのは反則?-- hira (2004/03/02 17:39:37 PST)
(slot-ref self 'hoge) ;;21文字 CLOS:フツーの書き方 this.getHoge() //14文字 Java:thisマニアが自己カプセル化したときの書き方 [self'hoge] ;;11文字 Gauche:slot参照案 by shiroさん this.hoge // 9文字 Java:thisマニア [hoge] ;; 6文字 Gauche:slot参照案 by hira(反則気味) hoge ;; 4文字 CLOS/Java:hiraが望む書き方
Shiro: 何をselfにします? define-methodは第一引数を特別扱いしませんよ。 ああ、そうじゃなくて、selfへの束縛は自分で作ってもいいのか。 うーん、暗黙の変数参照はいや〜んだなあ。それに、複数のオブジェクトが 絡むパターンで困りませんか。
例えば、オブジェクトyのa,b,c,dスロットの値をxにコピーするとき、 よくあるパターンはこんなんです:
(for-each (lambda (s) (set! (ref x s) (ref y s)) '(a b c d))
self明示だと:
(for-each (lambda (s) (set! [x s] [y s])) '(a b c d))
暗黙のselfにするとどう書きます?
xがselfであるならこうなりますね。
(for-each (lambda (s) (set! [s] (ref y s))) '(a b c d)) =>(for-each (lambda (s) (set! (ref self s) (ref y s))) '(a b c d))
selfの省略は自クラスではなく自インスタンスに対するものなので、片方のみが[]アクセスとなります。 「可視性とアクセッサのサンプル」のcf4と書けずにcf2にした感がありますね。 そもそもgeneric functionにクラス/インスタンスメソッドという区別が無いんだよなぁ。あえて言うならクラスメソッドか。 んー、クラス/インスタンスメソッドなんて言い出すと、またクラスの内外が問題になってくる。。。 つづきは可視性のところで。-- hira
- sが評価されることにすると、今度は直接名前を書きたい時は ['hoge] としなければならなくなります。 -- Shiro
- quoteの使い分けを強いるのはイヤですね。すんません。こりゃNGでした。 (まだまだマクロが分かってないんだな→私) -- hira
object-applyの利用
- 横槍ですいません。object-apply の利用なんてどうでしょうか?
スロットアクセスには見た目でシンボルよりキーワードが好きなので
自分用でこんな書き方してるんですが、邪道かな...nakamura (2004/03/02 22:06:39 PST)
(define-macro (define-class* name supers slots . options) (list 'begin `(define-class ,name ,supers ,slots ,@options) `(define-method object-apply ((object ,name) . rest) (let loop ((obj object) (arg rest)) (if (null? arg) obj (loop (slot-ref obj (string->symbol (keyword->string (car arg)))) (cdr arg))))))) (define-class* <foo> () ((bar :init-keyword :bar))) (define-class* <fee> () ((baz :init-keyword :baz))) (define fee (make <fee> :baz "baz!")) (define foo (make <foo> :bar fee)) (foo :bar) => fee (foo :bar :baz) => (fee :baz) => "baz!"
Shiro: これだと、object-applyを自分の目的に使いたいクラスが 困ってしまうんですよね。
可視性の制御
- クラスの中に入れないとしたら、generic functionによって自他の概念が無い以上、可視性の制御は提供出来ないのでは? 私は今fuyukiさんの所で発見したSoft Objectsにハマッてます。レキシカルスコープで、public/privateの概念が持てるし、hogeでアクセスできるし。何と言っても単純だし。でも、こいつに惚れるとGauche界では異端児となってしまう。。。諸刃の剣か(泣)-- hira (2004/03/02 18:08:30 PST)
Shiro: Scheme的には、「好きなOOPを使う」ってことでいいんじゃないですか。 共用するライブラリは何らかの共通フレームワークがあったほうがいいので あんまり毛色の違うマクロや名前がぶつかるシステムはまずいですが、 外に見せるのがクロージャだけ、というのならそういう問題もないと 思います。
このへんも参考になるかな:Scheme:制約の拡散
可視性の制御にも、他のメカニズムを持ち込むのではなくレキシカルスコープ 一本でゆくのが正しいと思うので、CLOSスタイルのスロット定義に うまくクロージャを絡められるとおもしろいとは思います。 例えばvirtual slotのsetterとgetter間で状態を共有するのに、今は インスタンスを介するしか方法がないですが、いちいちそのために 別スロットを作るというのはどうも汚い。 何か、クラス定義時点で、インスタンス作成時に作られる静的スコープ みたいなものが作れるとよさげです。
hira:うん。それが出来ればいいですね。 define-classの中にdefine-methodを書くようなイメージになりますか? そうなると「メソッドはクラスに属さない」という事から逸れそうだけど。
fuyuki: これは私も気になっているところです。 CLOSとクロージャというのを私はおおざっぱに 大小2本の刀があるようなイメージで捉えているんですが、 両者がうまく使い分けられるか? 協調できるか? といった点には いまだに自信がありません。 あと、CLOSは本当にSchemeになじむのか? ということも。
fuyuki: ちょっと余談ですが、私はこのところ 「多重継承の禁止」や「メソッドを束ねるクラス」は 「最適化として」正しいのかもしれないなんてことをぼんやり考えています。
- kou: 「多重継承の禁止」や「メソッドを束ねるクラス」って Ruby?みたい(メソッドを束ねるクラス->Module?)ですね.
- fuyuki: ああ、日本語が足りてませんでした「メソッドを束ねるものとしてのクラス」と言いたかったのでした。GFなやつでない、要するに普通のオブジェクトシステム。JavaとかRubyとかの。
- hira:名前の衝突を気にしなくて良い、てのも売りですね。
GF+moduleがあったとしても名前空間に対する不安はどうしても残るから。
gosh> (define-method hoge ((str <string>)) (list "gf str:" str)) #<generic hoge (1)> gosh> (define-method hoge ((c1 <char>) (c2 <char>)) (list "gf char:" c1 c2)) #<generic hoge (2)> gosh> (hoge "hello") ("gf str:" "hello") gosh> (hoge #\a) *** ERROR: no applicable method for #<generic hoge (2)> with arguments (#\a) Stack Trace: _______________________________________ gosh> (hoge #\a #\b) ("gf char:" #\a #\b) gosh> (define (hoge str) (list "norm:" str)) hoge gosh> (hoge "hello") ("norm:" "hello") gosh> (hoge #\a) ("norm:" #\a) gosh> (hoge #\a #\b) *** ERROR: wrong number of arguments for #<closure 0x10282ec0(str)> (required 1, got 2) Stack Trace: _______________________________________
- hira:上のような動作を不安に思っていたのでした。プライベートな関数のつもりで知らずに上書きした場合、自分に不都合はないけど、子供に怒られるかもしれない。後からダメな親だと言われたらつらいなぁと。
- fuyuki: 名前空間についてはCLOSでもそんなに不利はないというのがshiroさんの意見だったと思います(gauche-devel-jpの過去ログのどっか参照)。 私としてはまだ「本当にそうかな?」と半信半疑状態。
- hira: CLOSのちょっとイイ話:Lisp:Geometry。可視性の制御という問題は、プログラマをどう扱うかという、言語の立場の問題なのかもしれません。なに人が使う言語なのか、という問題。Javaは「プログラマ性悪説」に基づいているのを売りにしていたっけ。Cの場合は「プログラマ = 神」という立場をとってますね。Schemeの場合は「プログラマ = 言語設計者」という立場なワケだし(たぶん)。Gauche,CLOS,Scheme,Lispを使う人と局面を想定するなら可視性の制御に躍起になる必要は無いような気もしてきました。「子供に怒られる」なんて非常にまれなケースだし。
可視性とアクセッサのサンプル
- 静的スコープで出来ないこと:cf1,cf4 (class-private)
- やりたくないこと:cf3,cf5
- やりたいこと:cf2
Java
public class Hoge { private Object fuga; public Object getFuga() { return fuga; } public void setFuga(Object f) { fuga = f; } public void cf1(Hoge y) { fuga = y.fuga; } //NG public void cf2(Hoge y) { fuga = y.getFuga(); } //OK public void cf3(Hoge y) { setFuga(y.getFuga()); } //めんどい public static void cf4(Hoge x, Hoge y) { x.fuga = y.fuga; } //NG public static void cf5(Hoge x, Hoge y) { x.setFuga(y.getFuga()); } //めんどい }
Scheme:シンプルなメッセージパッシング
(define (make-hoge) (let1 fuga #f (define (self m . args) (define (get-fuga) fuga) (define (set-fuga! f) (set! fuga f)) (define (cf1 y) #f) (define (cf2 y) (set! fuga (y 'get-fuga))) (define (cfs y) (self 'set-fuga! (y 'get-fuga))) (define (cf3 y) (set-fuga! (y 'get-fuga))) (cond ((eq? m 'get-fuga) (apply get-fuga args)) ((eq? m 'set-fuga!) (apply set-fuga! args)) ((eq? m 'cf1) (apply cf1 args)) ((eq? m 'cf2) (apply cf2 args)) ((eq? m 'cf3) (apply cf3 args)) )) self)) (define (cf4 x y) #f) (define (cf5 x y) (x 'set-fuga! (y 'get-fuga)))
instance-privateとclass-private
privateといってもinstance-privateとclass-privateがある。 クロージャの束縛に「ドットで直アクセス」なんて出来ないということ。
instance-private class-private CLOS × × MPS ○ × Java × ○ Ruby ? ?(WRITE-ME)
- 私はJavaの挙動には馴染めません。今だに不思議な感じがします。--hira(2004/03/10 18:40:44 PST)
番外編:Message Passing Style (MPS)について
hira:MPSのスロットアクセスは、なかなか良い感じです。 でもそれ以外の面で、色々と不満があるのも事実。 MPS側の視点から理想を眺めてみよう、というコーナー。
- 新しい型になりたい: 現状では、型は常にプロシージャ。 あるプロシージャに対して、型を付与することって出来ないのだろうか。
- generic functionにかまってもらいたい: 型が常にプロシージャなのでgeneric functionが利用できない。 object applyとか、便利な機能を利用したい。
- メッセージのディスパッチ部分を書くのが面倒: 人間コンパイラにはなりたくない。
- ctagsがメソッド(メッセージ)を拾ってくれない: トップレベルでdefine*しないと拾ってくれないっぽい。
- 関数世界との関係にどう折り合いをつければいいのか: CLOSはgeneric functionにより関数世界にとけ込んでいる。 MSPは?関数世界をRubyのKernelやObjectのように扱えばいいのかしら?
※関数世界とは(proc obj arg...)という世界。オブジェクト指向世界は(obj proc arg...)となる。
Shiro: Gaucheのクラスは型システムって面もあるので(弱いけど)、 プロシージャを拡張するという考えではなく、新しい型をプロシージャ的に 振る舞わせるって考えはありますね。要はobject-applyを使うんですが。
舞台裏はこんな感じ。ただ、ユーザは気にする必要はありません。
(define-class <mps-meta> (<class>) ()) (define-syntax define-mps (syntax-rules () ((define-mps (name . args) . body) (define-mps name (lambda args . body))) ((define-mps name maker) (begin (define-class name () ((%maker :allocation :class :init-value maker) (%closure :init-keyword :%closure)) :metaclass <mps-meta>) (define-method object-apply ((class <mps-meta>) . args) (make class :%closure (apply (class-slot-ref class '%maker) args))) (define-method object-apply ((obj name) . args) (apply (ref obj '%closure) args)) name))))
以下のような具合に、ほぼクロージャベースのオブジェクトのように使えますが、 作られるオブジェクトはfooクラスのインスタンスになっています。
gosh> (define-mps (foo x) (lambda (msg . args) (case msg ((get) x) ((set!) (set! x (car args)))))) #<class foo> gosh> (define f (foo 4)) f gosh> (f 'get) 4 gosh> (f 'set! 5) 5 gosh> (f 'get) 5 gosh> (class-of f) #<class foo>
ディスパッチ部分に関しては、別途マクロを書くのがよいのでは。 それはdefine-mpsとはorthogonalに書けると思います。
hira:凄い。これでobject-*メソッドを定義出来ます。Gaucheの加護が得られるようになりました。やったー。
fuyuki:ディスパッチマクロの例としてはこんなのがあります。 http://lists.sourceforge.jp/mailman/archives/gauche-devel-jp/2003-January/000118.html
hira:上のメールから抜粋しときました↓。
> 3. case によるディスパッチはやっぱり格好悪い。
> 3はかなり一般的な問題だと思うので(gettext.scmでもやっている)、何か適当 > なユーティリティを提供したほうがいいのかもしれません。
そうっすねえ。このへんOO言語ならかえって悩まなくても いいんでしょうが… Gaucheのオブジェクトシステムだとこういうローカルな メソッドバインディングは扱いにくいですね。
実行する側からだと、メッセージによってディスパッチする 手続きは効率もそんなに悪くないですし、素直だと思うんですよ。 問題がコードの字面だけなら、こんなマクロを使ってしまえば:
(define-syntax dispatching-lambda (syntax-rules () ((_ method more ...) (dispatching-lambda-sub () () method more ...)))) (define-syntax dispatching-lambda-sub (syntax-rules (define) ((_ (symbol ...) (proc ...)) (lambda (message . args) (case message ((symbol) (apply proc args)) ... (else (error "unknown message" message))))) ((_ (symbol ...) (procs ...) (define (method . args) . body) more ...) (dispatching-lambda-sub (symbol ... method) (procs ... (lambda args . body)) more ...)) ))こんなふうに書けますね:
(dispatching-lambda (define (get) ...) (define (next seed) ...) (define (update! val) ...) (define (delete!) ...) (define (insert! key val) ...))こういうマクロをひとつ標準で持っておくと便利かもしれませんね。
symbolをapplicableにする
('hoge obj) --> (slot-ref obj 'hoge)
- yamasushi(2013/04/25 11:06:39 UTC)
というのはどうでしょうか? $マクロがあるので連鎖もコンパクトにかけますし。
- Shiro(2013/04/25 11:54:34 UTC): 面白いアイディアです。Clojureでキーワードをmap-likeなものに適用するとセレクタとして動作するのに似てますね。
特定の場面で便利なのは確かなので、採用するかどうかはメリットとデメリットの天秤になります。
デメリットというのは、こうして何でもapplicableにしてしまうと、動的型付け言語において オブジェクトの型を推測する手がかりが減っちゃうんですよね。上のようにリテラルで書いてあれば 問題ないですけど、 (a b) と書いてある時aがシンボルかもしれない、ってことになるので。
こういうのは一度導入しちゃうと引っ込められないので、臆病な私はなるべく 決断を遅らそうとするんですが、Clojureがかなり大胆にいろんなものをapplicableにしているのを見て まあ何とかなるかなと思いはじめてはいます。
ただ、この場合 (~ obj'hoge) としても1文字増えるだけですし、その1文字で式の意味が 明示できるなら敢えて短くする必要もないかなあ。
(map 'hoge objs) とかできるのはちょっと惹かれますけどね。- yamasushi(2013/04/27 05:58:57 UTC) x->^を作って見ました。(map (x->^ 'hoge) objs) のように書けます。
- yamasushi(2013/04/25 12:09:44 UTC) replの先頭文字が'なら括弧を省略できることにして、
gosh>'hoge obj ↓ ('hoge obj)を評価
もともとの動機はslot-refの引数並びが$マクロと相性が悪いというのがありました。
$でパイプラインを書いていると、cutばかり書かないといけないのが苦痛でありまして、 xslot-refみたいなものを考えたりしていたのですけれど、symbolそのものが関数になってもいいかなあとかと。
(clojureの->,->>のようなものがあれば、また別の話ですが。)
もしくは、$マクロの構文のなかで、シンボルが現れるとslot-refにするというのでも、いいかもしれない。と思い$マクロのソースを見たのですが、んが、となってしまいました。orz。簡単につかえるというのと、実装が簡単というのは別なんですね・・・・
あ、それと~だと、hash-tableのような、refを使ってしまったクラスのときに困るので、symbolをapplyすれば必ずslot-refになる、というのでなければいけないかなと思います。
- Shiro(2013/04/25 12:38:25 UTC): REPLでの操作はいかようにもできるので別に考えると良いと思います。
確かに$マクロによるチェインはスロット参照のチェインとは逆順になるので相性が悪いのはわかります。
でもHaskellのflipみたいなのを導入すれば式の流れは保存できますよね。冗長にはなりますが。
$ flip slot-ref 'hoge $ ...
ちなみにここでflipは(define (flip fn a b) (fn b a))
です。多引数に拡張しても良いでしょう。
- yamasushi(2013/04/26 12:25:56 UTC) Gauche:コンビネータプログラミングにflip,flipr,flipl,Gauche:万能アクセサを使うにflip~というものを付け加えました。(話がそれてしまいますが、Schemeにはリストのrotateってないのでしょうか? 置換とかは見つけたのですが・・・)
欠点
- オブジェクトの型を推測する手がかりが減る
利点
- (map 'hoge objs) とかできる
空気を読んでsymbolをlambdaにする
(define-method x->^ ((sym <symbol>)) (cut ~ <> sym) ) (define-method x->^ ((lst <list>)) (match lst [(x) ($ list $ (x->^ x) $) ] [(x . xs) (pack$ cons (x->^ x) (x->^ xs)) ] ) ) (define-method x->^ ((vec <vector>)) (match vec [#(x) ($ vector $ (x->^ x) $) ] [#(xs ... ) (^y (map-to <vector> (^z ((x->^ z) y) ) xs) ) ] ) )
('hoge obj) ---> ERROR (map (x->^ 'hoge) objs) ---> (map (cut ~ <> 'hoge) objs) (map (x->^ 'foo 'bar) objs) ---> (map (cut ~ <> 'foo 'bar) objs) ; x->^ は他の場合にも定義できそうな気がします。 ; refではなくslot-refを使いたいときはどうするか?という問題もあります。 ; もしくは、<collection>では問答無用に x->^するという選択もありかなとか。
- yamasushi(2013/04/26 03:23:07 UTC)
- yamasushi(2013/04/27 05:45:36 UTC) 実装してみました。
(x->^ '(name content) ) ; ---> 'name と 'content スロットを取得して、リストにする関数
applyよりも柔軟なapplyを定義する
(apply 'hoge obj rest) ---> ERROR (x-apply 'hoge obj '()) ---> (~ obj 'hoge) (x-apply 'hoge obj rest) ---> (cons (~ obj 'hoge) (apply x-apply 'hoge rest)) ; 実験的(どう書けばいいかよくわかっていないのですけど・・・) ; applyの末尾のリストの扱いをどうするかよくわからないのですが、感じとして: (x-apply 'foo 'bar obj1 obj2) ---> (list (~ obj1 'foo 'bar) (~ obj2 'foo 'bar) ) (x-apply '(foo bar) obj) ---> (list (~ obj 'foo) (~ obj 'bar) ) (x-apply '(foo . bar) obj) ---> (cons (~ obj 'foo) (~ obj 'bar) ) (x-apply #(foo bar) obj) ---> (vector (~ obj 'foo) (~ obj 'bar) )
- yamasushi(2013/04/26 03:23:07 UTC) つまり、左からsymbolなものをすべてとってきて、ref(or slot-ref)のキーにして、右からobjをとって、適用するという感じです。
(define-method x-apply ((sym <symbol>) . arg) (receive (syms objs) (span symbol? arg) (let1 refn (cut apply ~ <> sym syms) (match objs [(x) (refn x) ] [(xs ... ) (map refn xs) ] ) ) ) )
とりあえず、単純なケースから作って見ました。applyという名前じゃないほうがよかったような気もしてきました。
symbolとobjectの列が交互にあらわれるシーケンスをつかった参照構文
(define (%ref% refn pred . arg) ($ (^x (if (= (length x) 1) (car x) x ) ) $ map (match-lambda [( ((? (complement pred) obj) ) ( (? pred syms) ... ) ) (apply refn obj syms) ] [( ((? (complement pred) objs) ... ) ( (? pred syms) ... ) ) (map (cut apply refn <> syms) objs) ] ) $ flip slices 2 $ group-sequence arg :key pred) ) (define (%flip-ref% refn pred . arg) ($ (^x (if (= (length x) 1) (car x) x ) ) $ map (match-lambda [( ( (? pred syms) ... ) ((? (complement pred) obj) ) ) (apply refn obj syms) ] [( ( (? pred syms) ... ) ((? (complement pred) objs) ... ) ) (map (cut apply refn <> syms) objs) ] ) $ flip slices 2 $ group-sequence arg :key pred) ) (define (~~ . arg) (apply %ref% ~ symbol? arg ) ) (define (flip~~ . arg) (apply %flip-ref% ~ symbol? arg ) )
(~~ obj 'x) = (~ obj 'x) (~~ obj 'x 'y) = (~ obj 'x 'y) (~~ obj1 obj2 'x 'y obj3 'u 'v 'w ) == (list (~~ obj1 obj2 'x 'y ) (~~ obj3 'u 'v 'w ) ) == (list (list (~ obj1 'x 'y) (list obj2 'x 'y) ) (~ obj3 'u 'v 'w) )
- yamasushi(2013/04/26 19:59:30 UTC)
gosh> (~~ (find-module 'gauche) 'table) #<hash-table eq? 0x8204ed8> gosh> (~~ (find-module 'gauche) 'table 'cond-list) #<gloc gauche#cond-list> gosh> (~~ (find-module 'util.list) 'table) #<hash-table eq? 0x8398208> gosh> (~~ (find-module 'util.list) 'table 'cond-list) #<gloc util.list#cond-list> gosh> (~~ (find-module 'gauche) 'table (find-module 'gauche.generator) 'table) (#<hash-table eq? 0x8204ed8> #<hash-table eq? 0x82bd3c0>) gosh> (~~ (find-module 'gauche) (find-module 'gauche.generator) 'table) (#<hash-table eq? 0x8204ed8> #<hash-table eq? 0x82bd3c0>) gosh> (~~ (find-module 'gauche) (find-module 'util.list) 'table 'cond-list ) (#<gloc gauche#cond-list> #<gloc util.list#cond-list>)
gosh> (flip~~ 'table 'cond-list (find-module 'gauche) (find-module 'util.list) ) (#<gloc gauche#cond-list> #<gloc util.list#cond-list>)
- yamasushi(2013/04/26 22:47:24 UTC)これを使うと、スロットで比較する処理が:
($ apply = $ ~~ x y 'hoge 'foo 'bar)
のように書けます。
参照の分配(~の意味上の反転)
yamasushi(2013/04/29 06:00:10 UTC)slot-refが使いにくいと感じるのは、反対の意味をもつ働きをさせようとするからで、
(bunpai x 'a 'b 'c) == (list (~ x 'a) (~ x 'b) (~ x 'c) ) (values-bunpai x 'a 'b 'c) == (values (~ x 'a) (~ x 'b) (~ x 'c) )
のような演算子があればいいのではないでしょうか? つまり、~の意味を反転させたようなものです。 オブジェクトのほうをセレクタに作用させる、というイメージです。これとmatchやreceiveを組み合わせればいいのではないでしょうか?
(~ symbol1 symbol2 )の解釈
yamasushi(2013/04/28 12:07:31 UTC)selfがない場合について。
symbol1というモジュールのsymbol2という変数を参照する
globalなオブジェクトとしてモジュールシステムそのものがあると考える。
(~ 'gauche 'cond-list)
でgaucheモジュールのcond-listを参照する。
また、
(bunpai 'gauche 'scheme) == ( (シンボルから'gaucheモジュール変数をrefできるobj) (シンボルから'schemeモジュール変数をrefできるobj) )
と見なせる。
symbol1で指定したタイプのシステム情報にsymbol2で問い合わせる
この場合には、上のケースは
(~ 'module 'gauche 'cond-list)
のようになる。
(~ 'enviroment 'PATH )
でPATH環境変数を取得する。 また、
(bunpai 'environment 'module) == ( (シンボルから環境変数をrefできるobj) (シンボルからモジュールをrefできるobj) )
と見なせる。