Perlメインだった人からみたElixir

最近Elixirにふれる機会が有りましたので、理解を深めるためにも、見識を書いていきたいと思います。

なお、このエントリを書いている時点でElixir歴だいたい3日ほどです。いろいろ間違えているかもしれませんが、もし間違いに気づいた方、Twitterで教えてくれると嬉しいです。

私のメイン言語変遷

ここでいうメイン言語というのは、「業務で主に触っている(触っていた)言語」という定義でよろしくお願いします(他にもたくさん触ってますけど、かくの面倒なのでいろいろ端折ったりしてます)。

  • 1998: batch(MS-DOSのアレ)
  • 1999-2000: bash, batch
  • 2001-2002: bash, PHP, たまにPerl
  • 2003-2015: bash, Perl, たまにRuby
  • 2016-2018: JavaScript(Node.js), Swift, PHP, たまにPerl
  • 2019: JavaScript??

タイトルにPerlメインだった人って書いてるのは、多分自分で一番慣れている言語がPerlだからそうしている、という感じです。このエントリもPerl使ってる向けに書いているところがあるので、ご了承ください。

ちなみに、とってもお恥ずかしい話なんですけど、Elixirに触るまではElixirが動的型付け言語だということすら知りませんでした。

個人的感想「これPerlでは?」

少し触ってみて思ったのは、「これはRubyというよりPerlにだいぶ酷似してるな」ということでした。

Perlについては、比較的歴史のある動的型付け言語ということでよく知られているかと思います。そしてPerl自体はマルチパラダイムな言語なのですが、実はPerlのご先祖様はLispということもあって、関数型パラダイムの要素を多分に包含しているのです。

一方でElixirもまたマルチパラダイムな言語であり、関数型パラダイムの要素がふんだんに盛り込まれています。その上動的型付け言語だということになると、この時点でだいぶPerlに似ている感じがしますね。

Perlで言うところの「あれ」が「これ」

さて、ここからは具体的な例を挙げて、ElixirとPerlの機能ごとのマッピングを少しだけしていきたいと思います(並列性云々の話は、そこまでたどり着けていないので書きません)。

Cartonだとかcpmみたいなやつは「mix」

RubyでいうところのBundler、Node.jsでいうところのnpm、そしてPerlでいうところのCartonに相当するものとして、Elixirではmixというツールがあります。

このmixは、Perlでいうところの「Minilla」でもあります(パッケージ作成ツールです)。

例えばmy_modというパッケージを作成する場合は、mix new my_modを実行すれば、パッケージのひな形がmy_modフォルダに生成されます。このとき、assertionベースな検証手法が用いられたテストコードも同時に生成される点なんかは、minil newしたときとそっくりですね。

依存パッケージの指定は以下のように、mix.exsdefp deps doendの間につらつらと記入していくようです。

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    ]
  end

そして依存パッケージの導入はmix deps.getだけでOKとなります。

metacpanみたいなやつは hex.pm

ドメインがまさかの.pmなのでElixirはPerl!!!」というのは冗談ですが、Perlで言うところのmetacpan.orgに相当するのがhex.pmというサイトになります。

hex.pmはもともとErlangとElixirのパッケージ検索サイトなのですが、ElixirがErlangのラッパー言語だからか、Erlangで使われているエコシステムをそのまま使ってるようです。

例えばhttpクライアントが欲しい場合、hex.pmでhttp clientを検索すれば、いくつも該当します。

ただ、hex.pmにおける各パッケージのドキュメンテーションは、そのスタイルが統一されていない(CSSが全く違うというレベル)ので、読む側としては正直なんとかしてほしい気持ちはあります。きっとルールが定められていないからなんでしょうかね。。。

REPL(PerlでいうところのReply)は「iex」

標準でついてくるREPLはiexというものでして、必要十分かつ標準的な機能を持ちます。Perlで言うならばReplyが似たようなものかと思います(コチラは標準ではついてこないですが)。

Sigilは意味が違うけど、Perlにあるアレと似てる

Perlでは、Sigilというと変数の最初につく$@といった「変数の性質を決める記号」という事になっていますが、Elixirでは異なる意味の物となっています。それは、以下のような文字列リテラルや正規表現、文字のリストなどを表すためのものです。

// 文字列リテラル(エスケープ・式埋め込みあり)
strX = ~c/1 + 2 = #{1 + 2}/

// 文字列リテラル(エスケープ・式埋め込みなし)
strY = ~C/1 + 2 = #{1 + 2}/

// 正規表現
regex = ~r/(Perl|Elixir)/i

これらをiexで出力してみると、以下のような結果になります(IO.putsはperlで言うところのsayみたいなやつ)。

iex> strX |> IO.puts
1 + 2 = 3
:ok

iex> strY |> IO.puts
1 + 2 = #{1 + 2}
:ok

iex> "I like Elixir" =~ regex  
true

iex> "I like PHP" =~ regex   
false

iex> "I like Perl" =~ regex
true

正規表現の適用が=~なのもPerlと全く同じで、親しみすら感じます。

ところで、ElixirのSigilに相当するものが「演算子」という形でPerlにもあって、以下のように利用できます。

# 文字列リテラル(Elixirの~cに近いが、変数展開はするけど式展開はだいぶ特殊)
my $strX = qq/1 + 2 = @{[1 + 2]}/;

# 文字列リテラル(Elixirの~Cに同じ)
my $strY = q/1 + 2 = @{[1 + 2]}/;

# 正規表現
my $regex = qr/(Perl|Elixir)/i;

これらをsayしてみると、以下のような結果になります。

# 実行内容
use feature qw/say/;
my $strX = qq/1 + 2 = @{[1 + 2]}/;
my $strY = q/1 + 2 = @{[1 + 2]}/;
my $regex = qr/(Perl|Elixir)/i;
say $strX;
say $strY;
say 'I like Perl' =~ $regex;
say 'I like PHP' =~ $regex;
say 'I like Elixir' =~ $regex;
# 実行結果
1 + 2 = 3
1 + 2 = @{[1 + 2]}
Perl

Elixir

まとめ

ElixirとPerlの似たところをほんの少しだけ取り上げてみました。これをきっかけに、ElixirもPerlもちょっとでいいから利用者増えてほしいなぁ・・・

実は他にも似ている箇所が結構ある(構造体とパッケージの紐づけとか)のですが、このエントリはここまでにしたいと思います。この2つの言語、だいぶ似てませんか?私はかなり似ているなと思うんですが・・・。