関数プログラミングとElixir


はじめに

最近、Elixirに出会いました。とてもフレンドリーな言語でありながら、本格的な関数型プログラミング言語でもあります。武市先生訳のバード&ワドラー本を読んだ頃を回想しつつ、自分なりの関数プログラミングについて雑文を書きました。私は関数プログラミングについて正式な教育を受けておりません。間違いがありましたら編集リクエストをいただければ幸いです。

出会い

「関数プログラミング」という言葉、概念に出会ったのは武市先生訳の「関数プログラミング」(R.バード・P.ワドラー 共著)を読んだ時でした。奥付を見ると1991年4月20日初版発行とあります。あれからもう25年以上も経過したのですね。

本のカバーには次のように書かれていました。

引用
関数プログラミングはプログラミングを数学的な活動ととらえる考え方であり、本書ではそれを特定のプログラミング言語にはよらず数学の表記法を用いて紹介する・・・
引用終わり

読んでみると正しくその通りに書かれていました。高校数学程度の知識があれば十分に読み進められます。私は文系出身ですが何の問題もなく読み進められました。それどころかますますプログラミングの奥深さに魅了されました。その後、社会人を受け入れてくれる地元の国立大学の理学部数学科に入れていただき、数学の初歩を学びました。このバード&ワドラー本に感銘を受けたことも理由のひとつでした。

怖さ

私は関数プログラミングとは上述のことを言うのだと思い込んでいました。しかし、どうもそう単純なものでもなさそうなのです。関数プログラミングについて言及して議論が紛糾した事件のことを知り、素人が迂闊なことを述べるものではないと自戒していました。また、Haskellのことも少しだけ勉強したのですが早々と挫折してしまいました。圏論という数学が私にとっては高度でした。一応、複素関数論やベクトル関数の初歩まで教わり単位もいただいたので理解できるだろうか?とトライしてみましたが圏論の理解には至りませんでした。

     武市先生の本にあった数学とはそんなに高度なものだったのだろうか?

以後、関数プログラミングからは遠ざかってしまいました。

再会

関数プログラミングに再開したのは五味先生のLispの本でした。
「はじめてのLisp関数型プログラミング ――ラムダ計算からリファクタリングまで一気にわかる」
(五味弘 著)

2016年3月の出版が待ち遠しく、書店に予約しておいて初日に入手しました。とても平易に関数プログラミングを説明していました。とりあえずLispのsetqを使わない、代入による副作用を使わない、というのがこの本の主題でした。もともと1958年に登場した頃のLispはラムダ理論を借用しており関数プログラミングに近いものであったと思います。Lispはその柔軟性からその時々の最新のパラダイムを貪欲に吸収してきました。オブジェクト指向も取り込んでいます。本ではそれと対比するようにして関数プログラミングについて平易に解説していたように思います。いずれにしろ圏論どころか微積分も線形代数もでてきません。高校数学で十分でした。

Elixirとの出会い

Elixirに出会い、その平易で簡潔明瞭なことに驚きました。それでいてかなり本格的な関数型プログラミング言語であることがわかってきました。かつてのテレビ番組「暴れん坊将軍」の新さん、徳田新之助のようです。め組に居候する旗本の三男坊、気さくな新さん、実は徳川家八代将軍であった、というお話です。Prologを好む凄腕のプログラマとElixirの変数の仕組みについて議論を進めたところ、彼も驚くほどElixirは本格的な関数型プログラミング言語であることがわかってきました。

変換器としてのプログラム

Elixirのコードを見たときに特徴的なことにすぐ目が行きました。それはパイプ |> です。

defmodule M do
  def foo(x) do
    x |> bar |> boo |> uoo
  end

  def bar(x) do x+1 end
  def boo(x) do x*2 end
  def uoo(x) do x/3 end
end

iex(5)> M.foo(1)
1.3333333333333333

これは合成関数です。 uoo(boo(bar(x))) でもいいのですが、この |>を使った記述はいかにもベルトコンベアに部品を乗せて各工程を流れていくというイメージです。武市先生の本で言っていた「プログラミングを数学的な活動ととらえる」これに相応しいと思います。難しい数学はありません。高校数学の範囲内です。

数学の関数は状態を持ちません。定義域を与えれば値域が定まります。それは未来永劫、同じ結果をもたらします。状況を保存しておいてそれに依存する計算方法ではそれはできません。Elixirは初等数学で学んだ関数の性質をそのままに具現化していることがわかります。

他にも遅延評価による無限リストなどの機能がElixirには備わっています。バード&ワドラー本はMirandaという言語に近い言語で記述されていました。1991年当時、Mirandaは一般には入手できませんでした。そのため本の内容はSMLやSchemeを使って再現しながら学習したように覚えています。現在、モダンな言語として登場したElixirはバード&ワドラー本を試してみるのに最も相応しいように思います。

時代の要請

CPUの高速化は電子回路の物理的な頭打ちによりマルチCPUの方向へと進んでいます。これを活かすには並列に相応しいプログラミング言語が必要です。Elixirはそうした時代の要請に応えられるものの1つだと思います。並列、並行処理では状態を持つということが足かせになります。状態によって計算した値が異なる仕組みでは並列、並行処理が難しいからです。学問的な背景というよりは実際的なハードウェアを活かすという視点から関数プログラミングを取り込んでいるように私は感じます。複雑、かつ、大量化する現実のWEBなどの問題にあって、徐々に現在主流のオブジェクト指向から関数型へとパラダイムシフトが起きるのではないかと私は予想しています。そしてそれは学問的な要請というよりは現実の問題を解決するために必要とされているパラダイムであろうと私は思っています。

回顧(蛇足)

私は長らくLispを愛用していました。惚れ込んで自分でもISLispの処理系を作り、高速化させる工夫、型推論に取り組んできました。
https://qiita.com/sym_num/items/0e321959afc218772e33
それらはElixirにおいてモダンな形で実現されていました。素晴らしい才能をもつJosé Valimさんを尊敬してやみません。

竹内郁雄先生の「はじめての人のためのLISP」を読んで以来、Lispファンでした。しかし、どうも最近のLisp世界では私は異端児という感じでした。私はLispの中の関数プログラミング的なところが好きなのだということが明確になりました。それならばS式のLispに拘る理由はなにもありません。アルゴル系言語の表記で必要とあれば健全マクロも使えるElixirで全部OKという気持がしています。今後はElixirコミュニティにおいて微力ながら尽力していきたいと思っています。