In article <992533086.935976.4066.nullmailer / ev.netlab.zetabits.com>,
  matz / zetabits.com (Yukihiro Matsumoto) writes:

> |Proc#call 「だけ」に唯一の引数が配列であった場合に展開する処理を入れる
> |というのはどうでしょうか?
> 
> ということは
> 
>   proc{|a| p a}.call([1]) # => 1
> 
> ということですか? 今問題になっているのは、こっちではなく
> 
>   proc{|a| p a}.call(*[1]) # => [1] or 1
> 
> の方だと思うのですが。具体的な例を見せてくださいませんか?

えぇと、なんか考察が浅かったようで、これは撤回します。
# 後で深まった考察の特殊形として出てきますが、「だけ」というのは明らか
# に間違いでした。

> |Proc#call は多値と単値の境目なので、ここで変換されるのは納得できますし、
> |他のメソッド(例えば Proc#invoke などという別の名前を使う)を設けること
> |により、変換が行なわれないやりかたを提供することもできます。
> 
> Proc#yieldというのを用意しようと思っています(これは引数の数
> チェックなどを行わないつもりでした)。こちらにその機能を持た
> せることはありだと思います。

おぉ。

> |それに、Proc#call は代入の右辺の役割をもつくせに
> |
> |  ... = a,
> |
> |に対応するものが自然に記述できないというのも気になりますし。
> 
> というか、右辺の a, はそもそも許していませんし。

まぁ、そうなんですが。a,*[] と書いた方が適切だったかもしれませんが、原
さんの論点なので避けたんです。

> あ、でも
> 
>   proc{|a| p a}.call([1,2],*[])
> 
> が [1,2] になるという事実を発見してしまいました。うーむ。

これの原因はメソッド呼び出しにおいて
  o.m(a, *r)
と
  o.m(*[a, *r])
が等しいという挙動が理由だと理解しています。

一般には
  o.m(a1, ... an, *r)
は
  o.m(*[a1, ... an, *r])
に等しいわけです。(間違ってませんよね?)

これが意味するところはメソッド呼び出しっていうのは多値が基本だというこ
とです。Proc#call もメソッドですから、多値が基本です。そしてブロック引
数は単値が基本です。従って、Proc#call を呼び出してブロック引数で受け取
るとデータの入口が多値で出口が単値というミスマッチがおこります。そのた
め、なんらかの変換が起こります。

ここで、どうも何かが足りない気がしたので、すこし調べたところ、このよう
なミスマッチは Proc#call 以外にもあるようです。

データの入口には次のものがあります。
  単値: 代入の右辺, return, yield
  多値: メソッド呼び出し, Method#call, Proc#call, Continuation#call, (Proc#yield ?)

データの出口には次のものがあります。
  単値: 代入の左辺, メソッドの返り値, ブロック引数
  多値: メソッド引数

これらの組合せは次のようになります。
# やはり {単値,多値} -> {単値,多値} の 4種類あった...

単値 -> 単値
  代入の右辺 -> 代入の左辺
  return -> メソッドの返り値
  yield -> ブロック引数

単値 -> 多値
  yield -> メソッド引数                 (Method#to_proc)

多値 -> 単値
  メソッド呼び出し -> ブロック引数      (define_method)
  Method#call -> ブロック引数           (define_method)
  Proc#call -> ブロック引数
  Continuation#call -> メソッドの返り値

多値 -> 多値
  メソッド呼び出し -> メソッド引数
  Method#call -> メソッド引数
  Proc#call -> メソッド引数             (Method#to_proc)

で、実際の挙動をほんのすこし調べてみたところ、奇妙に思える挙動が発見さ
れました。

% ruby -e 'class A; def f(a); p a; end; end; A.new.method(:f).to_proc.call([1])'
1
% ruby -v
ruby 1.7.1 (2001-06-07) [i386-freebsdelf4.2]

この場合、Proc#call が入口でメソッド f の引数が出口なので、両側が多値
です。従って、普通のメソッド呼び出しと同様の挙動が期待されますが、残念
ながら配列の展開が起こります。
(なお、1.6.4 でも 1 になるが、なぜか 1.6.2 では [1] になる。)

というわけで、私の希望ですが、次のようなものです。

* 単値の入口から単値の出口へデータが通過する場合、代入(多重代入)のよう
  な挙動をすること。(代入の挙動自体が議論中ではありますが。)
* 多値の入口から多値の出口へデータが通過する場合、通常のメソッド呼び出
  しのような挙動をすること。
* 単値の入口から多値の出口へデータが通過する場合、変換が一回だけ起こること。
* 多値の入口から単値の出口へデータが通過する場合、変換が一回だけ起こること。
* wrapper を定型的に記述可能なこと。
* 単値から多値への変換は一種類であること。
* 多値から単値への変換は一種類であること。(Proc#call と Proc#yield で
  異なるとすればこれは無理?)

ただし、希望を満たす仕様がちゃんと存在するかどうか私にもわからないので、
かなわない希望なのかも知れないんですが...

# 私の案の延長線上でうまくいくかと思ったんですが、すこし考えた限りでは
# はうまくいかない...
-- 
[田中 哲][たなか あきら][Tanaka Akira]
「ふえろ! わかめちゃん作戦です$(C⊇」(Little Worker, 桂遊生丸)