真夏の怪談-生きていた亡霊

連日の「危険な暑さ」である。ボケかかった頭の体操として、Larry Wall,Tom Christiansen,Randal L.Schwartz「プログラミングPerl 改訂版」(O'REILLY)162pに興味のある例が出ている。

下記の例に出てくる「3」はどうなってしまったのだろうか。真夏の夜の幽霊のように消えてしまったのだろうか。かつてあった「地下鉄漫才」(古い!)ではないが、どうも落ち着かない。「それを考えると夜も眠れない」ほどである(笑)。
幽霊のように忽然と消えた「3」はどうなったのだろうか。どこかで亡霊として生き続けているのであろうか。そんなことを探ってみるのもいい頭の体操になるかもしれない。

参考 # (A) print(1+2) + 3; # 3と表示する # 表示された 3 は (1+2) の 3 である。では後の 3 はどうなったのだろうか。 # (B) print (1+2)+3; # これも 3と表示する! # 上とはスペースの位置が違うだけで結果は同じである。 # 表示された 3 は (1+2) の 3 である。では後の 3 はどうなったのだろうか。

メモ
(A)の場合も(B)の場合もほとんど変わらないので、まとめて書くと次のようになる(推測)。
  1. 「print(1+2)」の部分が関数のように見えるのでこれが最初に実行されて → 「3」が出力される。
  2. 後の 3 はもう処理のしようがなく行き場所がない → 結果的に無視されてしまう。

しかし、上の例を次のように改造すると、そのカラクリが少しわかってくる。
消えた「3」はこの世で亡霊として生き続けて、さまよっていることがわかってくる。成仏してはいないようである。

参考 # (A)の改造版 print 5, print(1+2) + 3; # 354 が表示される。 # (B)の改造版 print 6, print (1+2)+3; # 364 が表示される。

メモ
(A)の改造版の場合も(B)の改造版の場合もほとんど変わらないので、(A)の改造版で見てみる。
これで表示される末尾の「4」の部分に消えた「3」の亡霊が出てきている。
  1. printなどのリスト演算子のルール1)から、この場合は後のprintの方から実行される。
  2. 「print(1+2)」の部分が関数のように見えるのでこれが最初に実行されて → 「3」が出力される。
  3. そのprintが成功すると関数の戻り値として → 「1」を返す。ちなみに、失敗の場合は「0」を返す。
  4. その「1」と幽霊のように消えたはずの「3」とが「+」されて「4」になる。まさに生きていた亡霊である。
  5. そして最初のprintが「print 5, 4」として実行され → 「54」が出力される。
  6. 結果的に「354」が表示される。
NOTE
1) 同書88pの「2.5.1 項とリスト演算子(左方向)」の部分で優先順位についてのコメントがある。

(B)の改造版も上と同様にして「364」が表示される。

EXECUTE
上のサンプルの実行例(labo_0008)

- 2018/07/26 -


真夏の怪談(続)

外観上はカッコがあるかないかで大違いという形をしているが、これはリスト演算子の動作または優先順位の問題である。

参考 # (A) print 3, print 1, (1+1); # 1231 が表示される。 # (B) print 3, print (1), (1+1); # 1312 が表示される。

メモ
(A)の場合
  1. 「print 1, (1+1)」の部分が最初に実行されて → 「12」が出力される。
  2. そのprintが成功すると関数の戻り値として → 「1」を返す。
  3. その後「print 3, 1(この1はprintが成功したときの1である)」が実行されて → 「31」が出力される。
  4. 結局全体として「1231」となる。

(B)の場合
  1. 「print (1)」の部分が関数のように見えるのでこれが最初に実行されて → 「1」が出力される。
  2. そのprintが成功すると関数の戻り値として → 「1」を返す。
  3. その後「print 3, 1(この1はprintが成功したときの1である), 2」が実行されて → 「312」が出力される。
  4. 結局全体として「1312」となる。

この点について、「プログラミングPerl 改訂版」の次の部分が参考になる。
2.5.1 項とリスト演算子(左方向)
カッコがない場合には、printsortchmodのようなリスト演算子は、演算子の左右どちらの側に注目するかによって、優先順位がきわめて高いとも低いともいうことができる。
 @ary = (1, 3, sort 4, 2);
 print @ary;        # 1324と表示する
というコードでは、sort右にあるコンマsortを実行する前に評価されるが、sort左にあるコンマsortを評価した後で評価される。別の言い方をすれば、リスト演算子はその後ろに続く引数すべてを取り込み、演算子より前の部分から見ると、あたかも1つの項であるかのように振る舞うのである。
- Larry Wall,Tom Christiansen,Randal L.Schwartz「プログラミングPerl 改訂版」(O'REILLY)88~89p -
リスト演算子(List Operator)とは、一般的には、値のリストに対して作用する演算子だが、より限定的に(print, unlink, systemのように)引数リストをカッコで囲まなくてもよい演算子のことをいう場合が多い。
2つ並んだprintの後の方が最初に実行されること、そして全体としてこの行がどう実行されて、どういう結果になるのか、そのヒントになっている。

- 2018/07/27 -