Perl 6を見よう見まねで遊んているところを世間に発表するコーナーです。基本『かんたんPerl』の流れに沿って、Perl 5ではこうだったのがPerl 6ではどうなった、という形式で考察しています。てなことで今日はハッシュについて研究します。

Corned beef hash at the Creamery (Nina's breakfast)

 配列は、順番をキーにランダムアクセスできるデータでした。Perl 5で配列を使ったプログラムの一例はこうなります。

#! /usr/local/bin/perl
# arrP5.pl -- Perl 5で配列操作

use strict;
use warnings;
use 5.10.0;

my $num = shift;

my @month = qw (DUMMY Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
say "The month No. $num is $month[$num]";

 これは、月の順番を引数に得て、その月の英語名(略称)を返します。

[sample]$ ./arrP5.pl 3
The month No. 3 is Mar

 これは、月が1月から12月という順番を持つデータだからです。配列はゼロ始まりですが、ゼロ月という月はないので、先頭にDUMMYというデータを入れています。

 一方、ハッシュは、文字列を使って別の文字列を検索できるデータです。連想配列といいます。検索に使うデータをキー、キーによって検索されるデータを値と言います。
 ということで、ハッシュのプログラムの一例として、月名を引数に得て月数を返すプログラムを考えます。Perl5ではこうなります。

#! /usr/local/bin/perl
# hashP5.pl -- Perl 5でハッシュ操作

use strict;
use warnings;
use 5.10.0;

my $nam = shift;

my %month = (
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 );

say "The month named $nam is $month{$nam}";

[sample]$ ./hashP5.pl Apr
The month named Apr is 4

 このように、%monthというハッシュは%というシジルを持つが、それを検索する$hash{$nam}という式は$で始め(スカラーだから)、検索するキーはブレース{}で囲みます。
 ハッシュは順番が関係ないのでDUMMYは取りました。

 さて、これをこのままPerl 6に移植するとこうなります。

#! /usr/bin/env perl6
# hashP6.p6 -- Perl 6でハッシュ操作

sub MAIN (Str $nam) {
 my %month =
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 ;

 "The month named $nam is %month{$nam}".say;
}

[sample]$ ./hashP6.p6 May
The month named May is 5

 まず、代入文の右辺のリストの()を付けなくても良くなりました。
 次に、%monthというハッシュを検索する式もシジルは%のまま、%month{$nam};と書けば良くなりました。
 これはもう配列の回に見ましたね。

 ところで、こう書くとエラーになります。

#! /usr/bin/env perl6
# hashP6_2.p6 -- Perl 6でハッシュ操作2(エラー

sub MAIN (Str $nam) {
 my %month =
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 ;

 "The month named $nam is %month{$nam}".say;
 "BTW, the month named Dec is %month{Dec}".say;
}

[sample]$ ./hashP6_2.p6 Jun
===SORRY!=== Error while compiling /Users/query1000/Dropbox/kpc/sample/./hashP6_2.p6
Undeclared name:
Dec used at line 22

 {}の中にベアワードを書くと「定義されていない名前」と怒られます。これはコンパイルエラーです。こう書きます。

#! /usr/bin/env perl6
# hashP6_3.p6 -- Perl 6でハッシュ操作2(修正

sub MAIN (Str $nam) {
 my %month =
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 ;

 "The month named $nam is %month{$nam}".say;
 "BTW, the month named Dec is %month{'Dec'}".say;
}

[sample]$ ./hashP6_3.p6 Jul
The month named Jul is 7
BTW, the month named Dec is 12

 あるいはこうでもいいです。

#! /usr/bin/env perl6
# hashP6_4.p6 -- Perl 6でハッシュ操作3(修正2

sub MAIN (Str $nam) {
 my %month =
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 ;

 "The month named $nam is %month{$nam}".say;
 "BTW, the month named Dec is %month<Dec>".say;
}

[sample]$ ./hashP6_4.p6 Aug
The month named Aug is 8
BTW, the month named Dec is 12

 ここで<Dec>は前回でてきた、qw演算子の代わりになるもので、引用符を付けます。
 逆に変数で検索するときに%month<$nam>のように書くと、それは%month{'$nam'}と書くのと一緒だから、そんなキーの値はありませんと実行時エラーが返ります。
(「$nam月」というハッシュ要素を作っていれば別ですが。。)

 ということで、変数で検索する時とリテラルで検索するときで式が変わります。これはちょっとややこしいですね。

 ハッシュのキーを取り出すにはkeysメソッドを使います。

#! /usr/bin/env perl6
# hashP6_5.p6 -- Perl 6でハッシュ操作5

sub MAIN (Str $nam) {
 my %month =
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 ;

 my @mnames = %month.keys;
 "The month named $nam is %month{$nam}".say;
 "BTW, the month names are {@mnames}".say;
 "and their numbers are %month{@mnames}".say; # ハッシュ スライス
}

[sample]$ ./hashP6_5.p6 Sep
The month named Sep is 9
BTW, the month names are Nov Jun Mar Jan Dec Aug Oct Sep Jul May Apr Feb
and their numbers are 11 6 3 1 12 8 10 9 7 5 4 2

 月の一覧を表示していますが、早い順でも、アルファベット順でもありません。これは順不同です。アルファベット順にソートしてみます。

#! /usr/bin/env perl6
# hashP6_6.p6 -- Perl 6でハッシュ操作6

sub MAIN (Str $nam) {
 my %month =
  Jan => 1,
  Feb => 2,
  Mar => 3,
  Apr => 4,
  May => 5,
  Jun => 6,
  Jul => 7,
  Aug => 8,
  Sep => 9,
  Oct => 10,
  Nov => 11,
  Dec => 12,
 ;

 my @mnames = %month.keys.sort;
 "The month named $nam is %month{$nam}".say;
 "BTW, the month names are {@mnames}".say;
 "and their numbers are %month{@mnames}".say; # ハッシュ スライス
}

[sample]$ ./hashP6_6.p6 Oct
The month named Oct is 10
BTW, the month names are Apr Aug Dec Feb Jan Jul Jun Mar May Nov Oct Sep
and their numbers are 4 8 12 2 1 7 6 3 5 11 10 9

 月名でソートしてもいまいち意味がありませんが、Perl 5だったら

@mnames = sort keys %months;

と書いたところを、オブジェクト指向のPerl 6では

 my @mnames = %month.keys.sort;

となるところが面白いですね。%monthの、keysを取って、sortするということで、日本人にはこの方が分かりやすいような気がします。