2012-05-19 に行われた第1回 関数型言語勉強会 大阪の参加記録です。この記事を tweet するときは、#fpstudy のハッシュタグをつけていただくと参照しやすいです、よろしくお願いします。目次:
- あえて自己紹介的な何か
- 改善された発表スライドと発表の補足
- 他の発表者の皆様の発表まとめと感想など
- 懇親会での「公開しても構わない」ネタ
- 今後の課題、参考資料
あえて自己紹介的な何か(発表スライドには書かなかったので)
私の発表は LT でしたので余計なスライドは入れない方針をとりました。自己紹介しなかったのでこの場でします。いままでどんなプログラミング言語を触ってきたかについてだらだらと。
プログラミングを初めて知ったのはファミリーベーシック V1.0 でした。自分ではプログラムを書きませんでした。ただ、今は亡きベーマガの投稿プログラムを写経した記憶があります。ファミリーベーシックは言語仕様は面白くて、特にゲームを作るための独自命令がいくつもあったのを覚えています。省メモリプログラミングが必要で PEEK と POKE が飛び交うプログラムが至上とされ、良いゲームほどひどい(褒め言葉)プログラムでした。
次に触ったプログラミング言語は LOGO です。新宿 NS ビルでソニー様が主催した、親子で体験するプログラミング講座みたいなのがあったのです。非常に教育的な内容でした。しかし自宅には LOGO の環境がなく(今思えばファミリーベーシックで LOGO インタプリタ作ればよかったのかな…)それっきりで終わってしまいました。
高校に入学したときお祝いと称して PC-9801 DA (3.5 インチフロッピーモデル) を買ってもらいました。秋葉原の店員さんがとても教育的な人で、QuickBASIC と Quick C の両方を推薦してもらいました。QuickBASIC は非常に洗練されており、初めてまともに動くプログラムを自力で何か作った覚えがあります。一方、Quick C というか C は #include <stdio.h> の意味がわからないレベル(当時)だったのでまるで活用できませんでした。しかし、当時の MS-DOS 3.3C のメモリモデルとかアーキテクチャについてはぼんやりと把握した記憶があります。C でプログラムを書くようになったのは大学に入学してからです。友人は Nifty Serve に入っており様々な情報を入手してましたが、僕は入っておらず C プログラミングについてまったく無知だった。
大学に入ると NeXTSTEP が待ってました。NeXTSTEP に付随する Objective-C 1.0 開発環境はとても優れていて、いままでのプログラミングとは何だったのか…と思い知りました。在学中の 4 + 2 = 6 年間ずっと Objective-C でいろいろなものを作りました。特に LifeGame の実装が単位取得の条件になったので、GUI 含めてかなりキアイの入ったものを作りました。『ライフゲイムの宇宙』がすばらしい参考文献です。グライダー銃で仮想計算するとかやりましたね。#include <stdio.h> が何かがようやくわかった。それから Tcl/Tk の講習を受けて何か書きました。
NeXTSTEP は Unix がベースでしたがどちらかというとマイナーな部類でしたので fj.sources や anonymous FTP で提供されていたツールのビルドに失敗することが当たり前でした。そこで、ソースだけでなく configure や Makefile を自分で作りなおすという経験をしました。いま Gentoo がお気に入りなのはその影響もあります。
大学にはいって関数型言語にも触れました。Mathematica と Emacs Lisp です。プログラミング言語の視点から見ると当時の Mathematica はいろいろな不満点がありました。効率のよい計算をするためには関数プログラミングが不可欠でした。特に書換え系(term rewriting)の知識を持っていると計算が早く終わります。Mathematica でプログラム書くより Objective-C 使いたくなったので、Objective-C の C ブリッジで Mathematica の C API (MathLink) を叩くライブラリを書きました。イリノイ大学の人々がそういうことを独立にやっていたので、email で連絡を取り合いオープンソースをいじるという体験を初めてしました。API の重要性に気がついたのはこのときが最初で、いまでも設計の優れた API を見るたびに感心しています。当時の Emacs Lisp も別の意味でいろいろな不満点がありました。DRY 原則を保つために関数プログラミングが必要でした。YaTeX をいろいろカスタマイズしました。
博士後期課程の 3 年間では趣味で ruby 研究で C を使っていました。Objective-C が恋しかったので、つてを得て NeXT Station を一台手元に置いていました。ruby の C 拡張使ってライブラリを書いたら高林さんに使ってもらえたりしました。研究がスランプに陥っていたので、その代償としてプログラムばかり書いていました、この頃の話は前にも書いたけど。関数型言語も相変わらず Mathematica や Emacs を使っていたので何かをちまちまと書いてました。ruby の C 拡張で Mathematica の C API を叩くということもしました。述べたように Objective-C で書いた経験があったので難しいことは何一つないです。あと Mew を使い始めたので自分のためのカスタマイズを書いていました。Mew はすばらしかった。
関数プログラミングが業務になったのが就職後の一年目で、このとき初めて関数プログラミングが学問でもあるということを知り驚きました。fj.comp.lang.* は見てましたがプログラミングが研究として成り立つってのは頭に入ってなかった。そういえば、師匠は関数型言語のコンパイラを書いてそれで職を得ていたわけで、もっと早くからわかっているはずのことを、なにもわかっていなかった。2004 年に業務命令で Haskell を速習し ghc 6.4 を使って Haskell でプロダクツをいくつか書いて現在に至ります。卒業して 9 年目にしてようやく師匠の仕事ぶりを理解できる立場になりました。昔話を聞いてみたいものです。
まとめると、プログラミング言語遍歴は BASIC → LOGO → C / Objective-C / Mathematica / Emacs Lisp → Ruby → Haskell です。関数型言語の背後にある関数プログラミングの概念を学術的に学びはじめました。教科書だけでなく論文も読むようになりました。現在に至ります。今回の勉強会に参加するにあたって、「言語を問わず」って主催者の人に言われたので、わたしの身の回りにある関数型言語の処理系をいくつか触りました。いいきっかけになりました、ありがとうございます。
改善した発表スライドと発表の補足
今回補欠枠にもかかわらず発表の機会を下さった勉強会幹事の皆様に感謝いたします。
ところで勉強会のプログラムはだいたいが曖昧で、実際聞いてみると Haskell 固有の話題が特に注意なく散見されたので、発表寸前にスライドを増やしました。
まずは、入門編ということで、「関数型言語の基礎」について、勉強しませんか?
今回の勉強会は「関数型言語とはなんぞや」という考え方に重きをおこうと思いますので、特定言語にこだわるつもりはありません。
参加対象者:関数型言語に興味がある人。初学者〜中級レベル
ATND の勉強会のページより抜粋
次回は皆さんの発表がつながるように事前に打ち合わせしたほうがいいと思います。簡単なことではないということを理解していますがそのうえでよろしくお願いします。また、発表に対する質問時間をもっと用意してください。今回は質疑応答が足りませんでした(セッション枠で 30 分目一杯使った人が多かったこともある)にもかかわらず、最終的に時間は 20 分ほど余りました。懇親会に参加して質問しまくった方はそれが正解です。
わたしのスライドです。今では手に入りにくくなってしまった「関数プログラミング」の良書を集めてそれを紹介するというのが目的でした。ついでに今手に入る本も紹介しました。関数型言語全般の背景知識として持っておいて損はない情報です。べつにこれらのことを知らなくても関数型言語を使う業務に就けましたが(わたしのことです)事前に知っておいたほうが経験的によい事柄です。対象はオブジェクト指向はわかっているんだけど、関数型はよくわからないという人です。@tanakh さんのツイートと、@nushio さんの白眉の自己紹介文を断ることなく引用しました。お二人にはとても感謝しております。@nushio さんの表明「抽象化が実行速度を向上」は、誤解を生まないように気をつけて紹介しました。
ひとつ反省すべき点があって、OOP で抽象化・構造化するとき「クラス」を使うんだよって説明したんですが、プロトタイプベースな OOP の存在を忘れていました。だれか突っ込んでくださいよ。プロトタイプベースなら記述の自由度がそもそも高いので、抽象化構造化はプログラマのセンス次第でどうとでもなるでしょう。おわり。他にも反省すべきところがあるかもしれないので速やかに指摘してください。
@yoshihiro503 さんから「Real World Haskell は Haskell を学ぶうえで良い本ですか?」という質問をもらったと思うのですが、「現在ではよくないので次の版を待ちましょう」と答えました。Real World Haskell の初版は 2007-2008 年に書かれていて、ghc 6.8.2 のコードで溢れているので、現状の ghc 7 系列と互換性がなくなる具体例があり初心者がはまってしまうのでお勧めできなくなりました。写経ができないので非常に残念です。たとえば、19 章の divby5.hs は ghc 7 では違う書き方をします。ghc 7.4.1 で試してみるとこうなる:
-- file: ch19/divby5.hs
divBy :: Integral a => a -> [a] -> Maybe [a]
divBy = divByGeneric
divByGeneric :: (Monad m, Integral a) => a -> [a] -> m [a]
divByGeneric _ [] = return []
divByGeneric _ (0:_) = fail "division by zero in divByGeneric"
divByGeneric numerator (denom:xs) =
do next <- divByGeneric numerator xs
return ((numerator `div` denom) : next)
% ghci -ignore-dot-ghci
(snip)
ghci> :l "ch19/divby5.hs"
(snip)
ghci> :m + Control.Monad.Error
ghci> (divByGeneric 50 [1,2,0,8,10])::(Integral a => Either String [a])
*** Exception: division by zero in divByGeneric
(Real World Haskell Web 版 19 章では、
ここで Left "division by zero in divByGeneric が出てくることを期待している)
これをどのように直したら ghc 7.4.1 に対応するかは、次回以降のエントリをお待ちください…(きっと他の誰かがやる)初心者が写経すると混乱しますよね…あとは Control.OldException の話題とかですね… OldException は後方互換性のために残されてますが、この文章を書いているいまではその代わりに Control.Exception を使うことになってる。このような、ghc の歴史をちょろっと知ってる人がすぐ指摘できる程度の問題を解決できないのが Real World Haskell 初版の残念な点。
Real World Haskell(原著のほう)の次の版が出るらしいという噂は聞いていますがあくまで噂のレベルです(freenode #haskell で見た記憶が)。ghc は過去のバージョンのコードが動かなくなるような変更を平気でやるので(その代わりに新しく良い機能が次々と導入される)、Haskell のプロダクトを業務で使うにはいろいろ苦労することがあります。処理系のバージョンを気にしなければいけない点は Haskell に限らずどのプログラミング言語でも言えることですが。
「関数型言語は他のパラダイムの言語と比べて何が良いのか、勉強する前に教えてほしい」と質問されても答えに窮します。強いて言えば「読みやすく書きやすく短くなる」ことですが、これは関数型言語を理解していないと読めないし書けないし短くできないので、「いいから勉強してください」としか答えられません。わたしの能力不足です。「数学/英語/美術/etc.を勉強して何が良いのか、勉強する前に教えてほしい」という質問に似ています。豊かになるんですよ。
最近のプログラミング言語は関数型言語の良い部分を取り入れているので、関数型言語じゃなくてもいいという正論もあります。正直、現代の事情を鑑みると、関数型言語を自称する言語を勉強するメリットは昔に比べて減っています。関数型言語は簡単には習得できないし、何らかの理由で勉強したい or 上司に言われたので勉強せざるを得ないと思った人(わたしのような)が勉強すればいいでしょう。
何から勉強したらいいかわからない、その疑問はもっともで、誰か身近な guru に聞いてください。わたしもメールをもらったらお返事を書く程度には余裕があります。Twitter は今は止めています。
他の発表者の皆様の発表まとめと感想など
プログラム順ではなく、実際の発表順に感想を書きます。タイトルも ATND の仮ページにあるものではなく、できるだけ実際のスライドにあったものにします。講評できるほど偉くはないです。
たのしい関数型 by @s_kozake さん
スライドのほぼいたるところに突っ込まれるスキがあると思います。もし事前にスライドを公開していたら、もしかすると、皆さんの力を借りて直せたかもしれません。
@s_kozake さんとは懇親会でお話できました。とても感じの良い方です。お知り合いになれて良かった。願わくば今回のご発表を通じて間違えて理解しておられることを正していただきたいです…
今日からはじめる Clojure by @kuchitama さん
Clojure の丁寧な説明でした。インストールの方法から、leiningen の使い方、Clojure の導入まで。Kyoto.clj というミーティングの紹介。行ってみたいですが、次回の Kyoto.clj っていつどこでやるんでしょうね?
関数型って? by @kitora_naoki さん
この発表にも突っ込まれるスキがたくさんあります。Haskell を始めとする純粋な関数型言語の特徴を関数型言語の特徴と言うのは語弊があります。
記憶が確かなら、今回の勉強会の司会をつとめてくださった方です。ありがとうございました。
C#er が F# ちょろっと這い寄られた感想とか by @Posaune さん
F# の導入と IDE の紹介でした。IDE がある関数型言語 F# はすばらしいですね。あと、おまけスライドで紹介されていた、学習記録を GitHub で管理するテクニックはなるほどなと思いました。
ここで最初の休憩がありました。発表の突っ込みをしたかったけれど、その元気は自分の発表のために温存しなければならなかった。
プログラムを計算する話 by @uskz さん
わたしが関数型言語勉強会 大阪に参加したかった理由その 1. でした。その 2. は @syamino さんの話でそちらはあとで書きます。
@uskz さんらしい発表だったので皆さんにとってもよい休憩時間だったと思われます。わからない発表を聞くときは休憩すればいいんですよ?
数式は手書きでスキャンするのがいいですね。わたしもスキャナが欲しいです。発表の内容は Richard Bird & Oege de Moor の “Algebra of Programming” にある具体例の紹介でした。が、前口上として、なんで Algebra of Programming なのか?の部分が面白かったです。非常に怪しい前口上でした(褒め言葉)。非常によい本ですが古書なので高いです。
Algebra of Programming の内容(の第一章)は Haskell に限らず modern functional programming language における高等テクニックです。つまり簡約戦略が strict でも non-strict でも成り立つ話です。今回の集まりでは「関数型言語ならなんでも通用する話をせよ」という要求が主催者サイドからありました、という意味で適切な内容でした。@uskz さんが発表してなかったら、ぼくが代わりに同じ内容を発表していたかもしれません。
Algebra of Programming の最終章は貪欲法と運算を示します。@uskz さんはサービス良くこの最終章の具体例まで持ち込んだので、さすがに 30 分間で全部言うのはエクストリームスポーツだと思いました。次回に分ければもっとよかったのに。全部聞けたわたしにとってはありがたい話でしたが。
@uskz さんの話を日本語で知りたい人は「運算 プログラミング」というキーワードで検索しましょう。演算ではなく運算です。Google が勝手に「もしかして 演算」とお節介を焼きますが、運算で検索しましょう。運算は calculational program transformation の訳語です。『関数プログラミングの楽しみ』Jeremy Gibbons and Oege de Moor 著の 5 章 86 ページ目から読みはじめるのが簡単かもしれません。この本の運算の説明では圏論が陽に出てこないので(とはいえ 10 章の Arrow by Ross Peterson で圏論が出てくるのですが…)。
@uskz さんの発表の途中で出てきた Fokkinga の再帰定理 (Fokkinga’s mutual recursion theorem) は、@uskz さんの計算につかうものなのですけど、説明できるほど深くわかってないのでググってください。
途中まで補足を書いていたのですが、Web で可換図を書くことが非常に面倒なので、いつかやることにします。その代わりに、”Algebra of Programming” の第一章の最初の具体例を Haskell に書き直したものをお見せします。
-- よくある自然数 Nat の定義
data Nat = Zero | Succ Nat
deriving Show
-- 足し算
plus m Zero = m
plus m (Succ n) = Succ (plus m n)
-- かけ算
mult m Zero = Zero
mult m (Succ n) = plus m (mult m n)
-- 足し算とかけ算って、似てるよね?(えっどこがですか…よく目を凝らしてください)
foldn :: a -> (a -> a) -> Nat -> a
foldn c _ Zero = c
foldn c h (Succ n) = h (foldn c h n)
-- foldn を用いて plus, mult を書き直すと…
plus' m = foldn m Succ
mult' m = foldn Zero (plus' m)
@uskz さんは計算効率の面から fold を紹介していましたが、効率関係なくても説明できる概念です。plus’ がよりよく見えてきて、愛情がわいてきます。この例はあまりにも単純すぎますが、現実に使うコードでも同様のテクニックを用いてコードの改善(または改悪)ができます。プログラムの変換は重要な考え方で、その方法のひとつとして Algebra of Programming があります。foldn は天下りにやってきたものではなく、計算による理由付けから自然に導出されるものです。@uskz さんの手書きのスライドはそういう計算をやっています。まだいろいろ言いたいですが、紙面の都合上というか、この文章全体が書き終わらなくなってしまうので中途半端に終えます。
関数型脳になろう! by @its_out_of_tune さん
スライドをみてください、Java です。Java で何か見せればすごいと思いますが、なにもすごいところはスライドにはなかった…この次は型とワイルドカードでなにかやってくださいよ(わがまま)。
@its_out_of_tune さんとは懇親会で楽しくお喋りしました。東京からわざわざ来られていて体力と行動力に驚きました。@melponn さんの体力と行動力はふだんから見聞きしているのであまり驚かない。
わたしの発表がここでありました(前に述べたので省略)
Inverse FizzBuzz のはなし by @quassia88 さん
Inverse FizzBuzz の話でした。@quassia88 さんの GitHub リポジトリにマテリアルがあります。
Inverse FizzBuzz は問題を読んでから Haskell ならリスト内包表記とガードで瞬殺じゃないかなと考えました。実際 @notogawa さんのやりすぎでない方のコードと似たコードを考えていました。いま読むと、このコードにも、わたしが書いた(非公開)コードもバグがあるような気がするけど、わたしが疲れているだけだろうか?まあともかく宣言的に書けるのは間違いない。
スライド 26 ページにあるコーナーケースを突くテスト項目に感心しました。関数プログラミングでもテストは大事。
多相Variantの紹介 by @kyon_mm さん
@irof さんをいじるネタがまったく理解できませんでした。スライドの説明はわかりました。OCaml はすごい。
わたしが知る限り、Haskell に多相 Variant はまだなくて (ghc 7.4.1)、しかし似たことは 型クラスの変態拡張 すればいいという話があります。いつかさらなる変態拡張で入るかもしれないな、使い道がどこにあるかわからんけど。@keigoi さんのモジュールの集約に多相バリアントを使ってみたをあとで読む。香川先生の Polymorphic Variant in Haskell はその後どうなったんですかね?例によってOleg Already Did Itだったらしいが?
ラムダ計算で代数的データ型を表現する方法 by @syamino さん
@syamino さんはブログで説明しなおしています。発表スライドだけでなく記事も読みましょう。
λ計算の教養を積みましょうという話です。関数プログラミングだけをしていると、こういうことに気がつかないので、結果的に知識の浅いプログラマになってしまいます。それはよくない。
この発表を聞いた後は Mogensen-Scott encoding について調べればいいと思います。自明でない encoding があってそれのおかげでいろいろなことがつながります。
こういう話を聞くには質疑応答の時間が必要で、それが用意されていなかったのは残念でした。
スタート SML# by @keita44_f4 さん
スタート SML# の Ustream をすでに見ていたわたしにスキはなかった。何度でも同じことをいろいろな場所で紹介することはとても重要です。SML# のためのパーサライブラリとか作ったら喜ばれるのかしら。もうすでにあるのかな。
Haskell 入門 by @irof さん
スライドはこちら。
Haskell 入門というより、HSpec 入門でした。HSpec は大変よいものです。
関数型言語でプログラム書くときでもテストは重要です。テストのための標準言語はなんですか?といわれれば、それが xSpec (x にはいろいろなプログラミング言語の名前が入る)。xSpec には作法があって文法があって関数があって標準出力フォーマットがある。これらは、テストの標準言語として進化し改善されているので、オレオレテストフレームワークを使うくらいなら、xSpec を試したほうがよい。実装とテストはコードを分けるべきで、そういう意味で Python の doctest より xSpec のほうがよい。
懇親会での「公開しても構わない」ネタ
懇親会で一番重要なことは「席取り」です。つまんない人のそばに座ってしまうと、ひたすら食べて飲むだけの時間になってしまい非常に残念なことになる。次に重要なのは、あらかじめ話しておきたい事情を事前にまとめておくことである。
さすが Cr(ry) センセイやで。まあそれはともかく、わたしは @syamino さんの隣で @quassia88 さんの向いで大変よい席を取りました。背もたれがあるなしも見過ごしがちなポイントです。席取りがゲームの勝敗をにぎるカタンというゲームを毎日やるといいです。@melponn さんと @fadis_ さんがものすごい大声で話しまくっておられたので「ちょっとやめないか?」と言いたかったのを自省しつつ、お二人の仲の良さをうらやましく思いつつ、テーブルに話題を振る係をした。そういうことが好きなので。
まあだいたい聞きたいと思ったことは聞けた。なんかここで書きたいなと思ったことがあったんだけど、忘れてしまったぞ。「@syamino さん、そのまま君の道をつっぱしれ」と陰ながら思ったことだけは書いておく。@quassia88 さんとはいい酒を飲んだ(ぼくはウーロン茶でしたが)。終盤に各テーブルへ移動し一人残らず全員と挨拶しておしまい。
今後の課題、参考資料
「関数型言語の話題を初心者向けに話す」を字面通りに受け取って貴重な休日に話を聞きにきたひとたちには本当に申し訳ないことだと思う。まあだいたい勉強会はいろんな人がしゃべるので話題が散逸するのはしかたのないことだけれど。戦犯探しをしてもしょうがないので(ぼくが戦犯かもしれんし)、次回以降に改善してほしい。関西人ならツッコむところはツッコむべきやろ、そこ。
これからの方向性は3種類にわかれると思うので書いてみる。わたしが思いついてない他の選択肢は当然いろいろあると思います。
- 初心者〜中級レベル re-visited
- Getting started
- Killer applications
一つ目は単純に第一回の反省を活かして、初心者のひとの意見をもっと大事にする会にすること。あるいは二つ目は各関数型言語のインストールから Hello, world までの手順を紹介すること。これはスライドでなくても構わなくて、ただ URL を示せばいい。最後は関数型言語を使いたくなるようなスゴイ成果物を皆に見せること。ご検討ください。
(おまけ)実はお昼に焼肉の会があったのですが、それが楽しかったです。特に名古屋の皆さんとお会いできたのは幸いでした。企画してくださった @uskz さんに感謝です。なんばまで頑張って行きましたよ…
観測範囲内の参加記録一覧でおしまいにします、抜けてるのがまだあるかもしれない(Twitter の #fpstudy で検索):