Perl Hackers Hub

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

本連載では第一線の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リリース宣言も、この実装を念頭においての発言です。

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全般に通用する関数と、エコシステムについて扱います。

Perl 6のインストール方法

では、Perl 6をインストールしてみましょう。先述したようにPerl 6は仕様です。よって実際にインストールするのは、Perl 6の実装であるRakudoと、それを動かすためのMoarVM、NQPです。

インストールには主に2つの方法があります。

  • MoarVM、NQP、Rakudo、有用なモジュール一式をtarballにまとめたRakudo-Starをインストールする
  • Rakudo管理ツールrakudobrewを使って、MoarVM、NQP、Rakudoをそれぞれソースリポジトリから取得してインストールする

Rakudo Starのほうがすべて1つのtarballにまとまっていて簡単にインストールできますが、Perl 6の開発スピードが早いため古くなりがちという欠点があります。よって今回は、rakudobrewを使ったインストール方法を説明します。

rakudobrewを使ったインストール

rakudobrewをインストールしたのち、MoarVM、NQP、Rakudoをインストールします。

rakudobrewをインストール
$ git clone https://github.com/tadzik/rakudobrew \
  ~/.rakudobrew
rakudobrew/binにPATHを通す
$ echo 'export PATH=$HOME/.rakudobrew/bin:$PATH' \
  >> ~/.bash_profile
PATHを反映させる
$ source ~/.bash_profile
build moarでMoarVM、NQP、Rakudoをインストール
$ rakudobrew build moar
(5~10分間ほどかかります)

Rakudoをアップデートする場合は、rakudobrew build moarを再度実行してください。

外部モジュールのインストール

外部モジュールを使う場合は、モジュール管理ツールpandaをインストールしてから該当モジュールをインストールします。

次節でREPLRead-eval-print loopを使った説明をしますので、REPLを実行しやすくするためにLinenoiseという外部モジュールを入れておきましょう。

pandaをインストール
$ rakudobrew build panda
Linenoiseをインストール
$ panda install Linenoise

Linenoiseを入れることで、矢印キーによる以前実行した式の参照や、コントロールキーによるカーソル移動などができるようになります。

Perl 6はじめの一歩

それでは、Perl 6のはじめの一歩を踏み出しましょう! プログラミングの王道にのっとって、⁠Hello,World」と表示させます。

REPLでHello, World

perl6とだけ打てば組込みのREPLが起動しますので、まずはREPLで試します。

$ perl6
To exit type 'exit' or '^D'
> say "Hello, World";
Hello, World

p6ファイルでHello, World

次にファイルに書いて実行してみます。Perl 6は拡張子として、スクリプトの場合はp6、モジュールの場合はpm6を利用します[3]⁠。

hello.p6
use v6;
say "Hello, World";
実行
$ perl6 hello.p6
Hello, World

hello.p6の1行目にuse v6と書きましたが、これによって「このスクリプトはPerl 6である」と宣言しています。こう書いておけば、このスクリプトが誤ってPerl 5で実行された場合、次のようにメッセージで教えてくれます。

$ perl hello.p6
Perl v6.0.0 required--this is only v5.24.0

<続きの(2)こちら。>

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.130

2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8

  • 特集1
    イミュータブルデータモデルで始める
    実践データモデリング

    業務の複雑さをシンプルに表現!
  • 特集2
    いまはじめるFlutter
    iOS/Android両対応アプリを開発してみよう
  • 特集3
    作って学ぶWeb3
    ブロックチェーン、スマートコントラクト、NFT

おすすめ記事

記事・ニュース一覧