Perl Hackers Hub

第39回 Perl 6の歩き方―15年越しでリリースされた新バージョン(1)

この記事を読むのに必要な時間:およそ 3 分

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーは鍛治匠一さんで,テーマは「Perl 6の歩き方」です。

Perl 6リリース!

2015年のクリスマス,Perlの生みの親であるLarry Wallのポエム的なブログポストとともにPerl 6がリリースされました。2015年1月31日~2月1日に開催されたFOSDEM 2015で「今年のクリスマスにリリースする!」と彼が宣言してから開発ペースが急激に上がり,なんとかリリースにこぎつけた感じでした。

今回は,そのPerl 6の歩き方を紹介します。具体的には,Perl 6のインストール方法,特徴的な関数の文法,そしてモジュールのエコシステムについて扱います。

なお,リリースされたとは言っても,安定性,完成度においてPerl 6はプロダクション環境で使えるレベルにはまだ到達していません。しかし魅力的な文法が目白押しで,何より書いていて楽しいです。本稿がPerl 6に興味を持つきっかけになればうれしく思います。

リリースまでの道のり

簡単にPerl 6の歴史を振り返ります注1)。

今から16年前の2000年にPerl 6プロジェクトは始まりました。そのころPerl 5のソースコードは非常に複雑になっており,新たな機能を加えるのが難しくなっていました。そこでPerl 6プロジェクトでは,次世代を担うPerl 6のあるべき姿を考え,まず仕様を書くところから始まりました。この考えは今でも続いており,Perl 6は仕様であり,その実装がいくつか存在する,という構図になっています。

2005年,HaskellによるPerl 6実装のPugsが登場します。そして2008年には仮想マシンParrot上で動くPerl 6実装のRakudoが登場しました。その後,Rakudoは仮想マシン上で直接実装するのではなく,仮想マシン上でPerl 6のサブセット言語であるNQPNot Quite Perlを動かし,NQPでRakudoを実装するというように変わっていきました。

2016年現在では,仮想マシンがParrotからMoarVM(もしくはJVM)に変わり,「MoarVM+NQP+Rakudo」が最も完成度の高いPerl 6実装となっています。LarryのPerl 6リリース宣言も,この実装を念頭においての発言です。

注1)
2009年までの歴史については,gihyo.jpでの連載「モダンPerlの世界へようこそ」第14回Rakudo:実装する方法だってひとつではないのですに詳しい説明がありますので,ぜひこちらもご覧ください。

Perl 6の長所

実際にPerl 6に触る前に,筆者の考えるPerl 6の長所を紹介します。

文法が多く表現力が豊か

Perl 6に少し触れてみればわかりますが,覚えるべき文法はかなり多いです。一方でそれは,その豊富な文法を駆使すればPerl 5よりも簡潔に,効果的にプログラムが書けるということです。

たとえばPerl 6にはジャンクションという機能があります。ジャンクションとは同時に複数の値のように振る舞える1つのスカラのことで,これを使うと次のように簡潔に書けます。

Perl 5の場合

if ($n == 1 || $n == 3 || $n == 5) { ... }

Perl 6でジャンクションを使った場合

if $n == 1|3|5 { ... }

オブジェクト指向,メタプログラミングのサポート

Perl 6はいろいろなプログラミング手法をサポートしています。特にオブジェクト指向については必要十分な機能が備わっています。また,メタプログラミングについても意欲的にその機能を実装しています。

Perl 6では,classキーワードでクラスを,hasキーワードでメンバー変数を定義できます。また^からはじまるメソッドによってクラス自身を操作することができます。

# クラスの定義
class Person {
  has $.first-name;
  has $.last-name;
  method name() {
    $!first-name ~ ' ' ~ $!last-name;
  }
}
my $me = Person.new(
  :first-name<Shoichi>, :last-name<Kaji>
);
say $me.name; # Shoichi Kaji

# メソッドの動的追加
Person.^add_method: 'greet', method () {
  say "Hi, my name is {self.name}.";
};
$me.greet; # Hi, my name is Shoichi Kaji.

強力な正規表現

Perlはもともとテキスト処理のために作られたプログラミング言語です。そしてテキスト処理の中心的な役割を担うのが正規表現です。Perl 6ではこの正規表現がさらに進化しました。

正規表現はややもすると複雑になり,可読性が悪くなります。Perl 6は正規表現を部品に分け,構造的に定義できるGrammarというしくみでこれを解決します。たとえば,

setting.ini

second=b
hits=42
perl=6

のようなkey=valueからなる設定ファイルをパースするコードは,次のようになります。

# https://doc.perl6.org/language/grammarsから
# 一部改変して抜粋
grammar KVPairs {
  # 与えられた文字列は
  # TOPでテストされパースされる
  token TOP { [<pair> \n+]* }
  token ws { \h* }
  rule pair {
    <key=.id> '=' <value=.id>
  }
  token id { \w+ }
}

class KVActions {
  # $/でマッチオブジェクトを受け
  # それの処理方法を記述していく
  method id($/) {
    $/.make: ~$/;
  }
  method pair($/) {
    $/.make: $<key>.made => $<value>.made;
  }
  method TOP($/) {
    $/.make: $<pair>».made;
  }
}

my $content = "setting.ini".IO.slurp;

# grammar KVPairsで$contentをパースし
# KVActionsに従ってそれを処理する
my $res = KVPairs.parse(
  $content, :actions(KVActions)
).made;

for @$res -> $p {
  say "Key: $p.key()\tValue: $p.value()";
}
# Key: second Value: b
# Key: hits Value: 42
# Key: perl Value: 6

grammar KVPairsで文字列をどのようにパースするかを定義しています。KVPairs.parse($content,:actions(KVActions))が呼ばれると,$contentKVPairsTOPとのマッチが試されパースされます。class KVActionsはそのパースされた結果をどう扱うかを定義しています。

並行/非同期プログラミングのサポート

Perl 5の大きな欠点に,言語として並行/非同期プログラミングをサポートしていないことがあります。これを踏まえPerl 6では,中核機能として並行/非同期プログラミングのしくみをサポートしています。

たとえば以下は,HTTPリクエストを並行に行うコードです。start {}によって非同期にHTTPリクエストを発行し,awaitによってそれらが終了するのを待っています。

sub http-get($url) { ... }
my @url = (...);
my @result = await @url.map: -> $url {
  start { http-get($url) };
};

以上,筆者が考えるPerl 6の長所を4つ挙げました。なお,ここに挙げたGrammar,並行/非同期プログラミングなどについては,それ自体で閉じたトピックであるため本稿ではこれ以上扱いません注2)。その代わり,Perl 6全般に通用する関数と,エコシステムについて扱います。

注2)
興味のある人は,10月20日(木)公開の第39回(3)「さらに学ぶためのリソース」を参照してください。

著者プロフィール

鍛治匠一(かじしょういち)

1984年神奈川県生まれ。ヤフー株式会社所属。

広告配信システムの開発,運用をしている。

いつも,すきあらばPerlで開発しようと画策している。

GitHub:https://github.com/skaji

コメント

コメントの記入