joinクイズ の解答と解説です。
joinクイズ 第1問の答え
perl -E 'say join "0" .. "9"'
join
の関数プロトタイプを見ると、以下のようになっています。
$ perl -E 'say prototype \&CORE::join' $@
よって、第一引数はスカラコンテキストで評価されます。
範囲演算子 ..
のドキュメント を見ると、以下のように書いてあります。
In scalar context, ".." returns a boolean value
よって、 "0" .. "9"
は boolean となりますが、デリミタのみが指定されていて join
対象のリストが空リスト ()
であるため、出力も ""
となります。よって、答えは、
1. 何も表示されない
です。
joinクイズ 第2問の答え
perl -E 'say join "0" .. "9", "a" .. "z"'
第1問と同様に考えると、この join
は、デリミタが "0" .. "9"
で、対象となる文字列のリストが "a" .. "z"
と解釈できます。よって、アルファベット a ~ z を、 "0" .. "9"
で連結した文字列が答えです。
さて、 "0" .. "9"
は真偽値とのことですが、実際にどのような値となるかはドキュメントをしっかり読まなければわかりません。範囲演算子のドキュメントから必要な記述を抜粋すると、まず、
It is false as long as its left operand is false. Once the left operand is true, the range operator stays true until the right operand is true
とありますので、この演算子は「第一引数が真となってから、第二引数が真となるまで、ずっと真値を返す」ということがわかります。 "0"
は偽値なので、これだけだと偽値が返りそうなものですが、先を読むと次のような記述があります。
If either operand of scalar ".." is a constant expression, that operand is considered true if it is equal (==) to the current input line number (the $. variable).
つまり、 "0" .. "9"
は、 ($. == '0') .. ($. == '9')
と同値です。ファイルの読み込みを行っていないため $. == 0
が成立するので、真値が返ります。
では、真値がどんな値かというと、ドキュメントにこのように書かれています。
The value returned is either the empty string for false, or a sequence number (beginning with 1) for true
つまり、ここでは 1
が返るということです。よって答えは、
3. a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1x1y1z
となります。以下のように、事前に $.
の値を改変すると答えが変わります。
$ perl -E '$. = 1; say join "0" .. "9", "a" .. "z"' abcdefghijklmnopqrstuvwxyz
また、 for
でループさせると、デリミタがインクリメントされていく様子が見られます。
$ perl -E 'say join "0" .. "9", "a" .. "z" for 0..2' a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1x1y1z a2b2c2d2e2f2g2h2i2j2k2l2m2n2o2p2q2r2s2t2u2v2w2x2y2z a3b3c3d3e3f3g3h3i3j3k3l3m3n3o3p3q3r3s3t3u3v3w3x3y3z
joinクイズ 第3問の答え
perl -E 'say join "a" .. "z", "0" .. "9"'
ここまでの問題と同様に考えると、 "a" .. "z"
で 0 ~ 9 までの文字を連結したものが答えになるということがわかります。
問題は、 "a" .. "z"
を評価するとどうなるかです。第 2 問で見た通り、この式は ($. == 'a') .. ($. == 'z')
と等価であり、 $. == 0
です。 Perl で数字じゃない文字列を ==
比較すると 0
となりますので、範囲演算子の第一引数も第二引数も真と評価されることになります。
ここまで読んだ規則だと、 "a" .. "z"
は 1
となりそうなのですが、範囲演算子のドキュメントにはもう一つ、以下のような記述があります。
The final sequence number in a range has the string "E0" appended to it,
$. == "z"
ですので、この範囲演算子は次回から偽値を返します。つまり、これが最後の真値の連番です。よって、 1
の後ろに "E0"
がつけられた、 "1E0"
がデリミタとなります。よって答えは、
3. 01E011E021E031E041E051E061E071E081E09
となります。