だるろぐ

だるいぶろぐです

perlは見た目が重要という話

突然ですが以下の実行結果を予測してください。ついでに実行結果と照らし合わせてみてください。

% perl -le 'print 3 ** 2'
% perl -le 'print (1+2) ** 2'
% perl -le 'print (3) ** 2'







見ただけでオチが分かりましたが何か? → 尊敬させてください
予想通りでしたが何か? → 尊敬させてください
何これ分かんないけど自分で調べるからいいや → さようなら
何これ教えろ → 下に進む

実行結果

こうなる。

% perl -le 'print 3 ** 2'
9
% perl -le 'print (1+2) ** 2'
3
% perl -le 'print (3) ** 2'
3

解説

perlは先の3つの例は、それぞれ以下のように解釈・実行する。

% perl -le 'print 3 ** 2'

3 ** 2 を行った結果をprintする

% perl -le 'print (1+2) ** 2'

print(1+2) を行い、その結果を ** 2 する

% perl -le 'print (3) ** 2'

print(3) を行い、その結果を ** 2 する


というわけで、カッコがprint関数を呼び出すときに使われていたのでした。
納得できない人は

% perldoc perlfunc

もしくは http://perldoc.jp/docs/perl/5.6.1/perlfunc.pod を。

関数に見えるならば、それは関数で、優先順位は関係ありません

と。perlは、printの後ろに () があったからこれはprint関数を呼び出すのに使ってるんだな、と解釈したのでした。

解説2

  • print の結果を ** 2 するって何やねん
    • perldoc -f print
Returns true if successful.

printに成功したら真を返す。で、その真とやらはスカラ・アレイのどちらのコンテキストで評価しても 1 だった。この例だと左辺で変数に受け取ってないのでvoidコンテキストだけど。

  • printの返り値が 1 か。じゃあ 1 ** 2 ってことになって 1 って出力されるはずじゃないの
    • この例でいうと出力は副作用みたいなもんです

先の例でprintが行ったのは、あくまで自分に与えられた引数を出力しただけ。この「与えられた引数」っていうのは、それぞれ 3 ** 2 と (1+2) と (3) だ。
print関数からすれば、

  1. 自分は与えられた値を出力した
    • それぞれ 3 **2 = 9, (1+2) = 3, (3) = 3 だった
  2. 自分の仕事は終わった

だけなのだ。しかし例の2個目と3個目ではperlに食わされた命令はそれで終わらず、

  1. print関数の仕事の結果(つまり1)に ** 2 するよう命令された
  2. しかしその結果を受け取る左辺が居ない…何だこの無駄な計算は…

という。


実はこれはwarningsプラグマを使えばちゃんと警告してくれる。

% cat t.pl
use warnings;

print 3 ** 2;
print (1+2) ** 2;
print (3) ** 2;

% perl t.pl
print (...) interpreted as function at t.pl line 4.
print (...) interpreted as function at t.pl line 5.
Useless use of exponentiation (**) in void context at t.pl line 4.
Useless use of exponentiation (**) in void context at t.pl line 5.
933

最初のワンライナーだとwarningsプラグマが有効になってないから何も言われない。
言ってもらうには -w を使う。

% perl -wle 'print 3 ** 2'
9

% perl -wle 'print (1+2) ** 2'
print (...) interpreted as function at -e line 1.
Useless use of exponentiation (**) in void context at -e line 1.
3

% perl -wle 'print (3) ** 2'
print (...) interpreted as function at -e line 1.
Useless use of exponentiation (**) in void context at -e line 1.
3


以上。
今日つまづいたところでした。
そうだ海外にも同じところでつまづいた人が居た。
http://www.webmasterkb.com/Uwe/Forum.aspx/perl/26758/1-0-1










  • そんなん知るかよ!そもそもそんな変な解釈すんじゃねーよめんどくせえ、perlはそんくらい分かれよ!
  • 全くだよな!ruby使おうぜ!
% ruby -e 'puts 3 ** 2'
9
% ruby -e 'puts (1+2) ** 2'
9
% ruby -e 'puts (3) ** 2'
9

ruby万歳!