top page > culture > books > computer > sugoih
更新日:
文責: 重城良国

「すごいHaskellたのしく学ぼう」

(工事中 10%)

売れた理由

キャッチーなタイトルと装丁

この本が売れている一番の理由はタイトルの「すごい」と「たのしく」にある。Haskellというものが「何かすごそう」なのは多くのプログラマが知っている。「でも難しいんでしょう?」が次にくる言葉だろう。それを「たのしく」学べると言う。「たのしく」と平仮名で書いてあるしイラストもジョークもゆるい感じだ。そこで「簡単に学べそう」と思う。そんなに厚くもないし、と。

さらにタイトルを分析すると「緊張と弛緩」があるように思う。まず「すごい」は「一体何がすごいのか」という期待感を持たせる。そして「Haskell」という言葉は「難しい」という感想を持たせるが、その次の「たのしく学ぼう」で緊張がほぐれる。そういうリズムのようなものがあるように思う。

とくに「すごい」の部分は「どのような点ですごいのか」という疑問を抱かせる漠然とした言葉でありタイトルとしては秀逸に思う。

親しみの持てる話り口

ちょいちょいゆるい感じのジョークもありなんとなく親しみも持てる。

既存Haskellerからの支持

Haskellを1通り学び終えてからこれを読むといろいろと発見がある。そのため、既存のHaskellerからの支持は得やすくなっている。知識の穴を埋めるのには良いかもしれない。

そのため既存のHaskellerが初心者に勧めがちだ。

問題点: まとめ

一言で言えば「つめこみすぎ」だ。もうすこし取捨選択し入門レベルの話、初級レベルの話、中級レベルの話のように分けたほうが良いだろう。

総合的な問題点

基礎的なことの説明が不十分

例を挙げるうえでいろいろと構文等の知識が必要となる。そのために、はじめにいろいろな知識が羅列されてしまっている。

たしかにアプリカティブやジッパーは魅力的だけど

魅力的ではあるけれど各論的な話である。

著者が書きたいことだけを書いている

著者が「ここを説明したい」というところだけが説明されている。基本的なところの説明は不十分である。

学ぶ順番が熟慮されていない

「たのしく」学ぶためにはいろいろな例を挙げていくことが必要だ。そのためには例を挙げるのに最小限必要なだけの知識からはじめて、同様の考えかたですこしずつ知識を増やしていく必要がある。そのような「学ぶ順番」の考慮が不十分だ。

基本的な内容と応用的な内容が混ざっている

これがわからなければHaskellはわからないという基本的な内容と、より応用的で各論的な話とがごっちゃに説明されている。

イラストはとくに内容と関係ない

キャッチーなイラストは望ましいが、とくに内容とは関係ないので理解を助ける役には立たない。単なるアイキャンディーだ。

詳細: イントロから第10章まで

イントロダクション

以下の内容について説明していて良い。

前置きが短いのも良いと思う。

第1章のリスト以前

対話環境でいろいろな値や関数適用等を試している。手を動かして学び始められるので良い。ファイルで関数を定義して対話環境に読み込む方法の説明も良い。

第1章のリストの説明について

リストの本質は「くりかえし」だ

これに関してはどちらが良いのか難しいところだ。たしかにリストをデータ構造として提示することは初学者にはわかりやすい。反面、配列を使うべきところにリストを使うことで効率上問題のあるコードを書き、その反動でリストを軽視することにつながる。

個人的にはリストは「くりかえし」を置き換えるものととらえるべきと感じている。

リストの説明が雑

リストについてはその使いかたを含めて具体例を挙げてじっくりと説明する必要がある。それはベストプラクティスに関する話でもある。再帰を扱う前にリストによってできる範囲を理解しておくことが良いだろう。Haskellによるコーディングの大きな部分を直接的な再帰よりもリストで行うということを考えればリストについてじっくりと学ぶ必要があるのは当然のことだ。

リスト内包表記の説明が早すぎる

リスト内包表記をさきに説明するのはあまり良くない。例を挙げるのには役立つがあまり早くに説明すると学習者の気がそれてしまう。リストを扱う関数をいろいろと学んだあとが良い。あるいはリストモナドの別の書きかた、くらいの扱いでも良いように思う。

第1章のタプルの説明について

タプルの説明をリストからの類推で行っているのは良くない。2つはまったく違うものだ。

第2章 型の説明について

対話環境でいろいろな値の型を表示させているのは良い。型変数の話は多相関数を学んでからでないと意味がよくわからないかもしれない。

関数について学んだあとが良いように思う

たしかに型は重要だ。しかし、型の説明は関数の説明のあとで良いと思われる。関数の説明をしたあとに、型の不一致によるエラーの例を出しながらのほうがわかりやすいだろう。

型クラスの説明が早すぎる

第2章で型クラスの説明をしている。そしていろいろと型クラスの例を挙げている。たしかにHaskellの標準的な関数の多くは多相的であるので、さきに説明しておきたい気持ちはわかるが、ここでそれを説明するよりはとりあえずはしれっと使っておいて、あとになって「実は多相的でした」とタネ明かしするほうが学習しやすいだろう。

型クラスの列挙は単なるつめこみになってしまっている。「型クラスの良さ」がわからない。

関数の説明について

いきなりパターンマッチはどうかと

たしかにHaskellの仮引数はパターンだ。しかし、まずは普通にパターンマッチを意識しないで関数を書くことを学んだほうが良いだろう。また、パターンマッチの説明をするなら、その2つの機能をセットで教えたい。よってMaybe型を導入してJust値とNothing値への分岐とJust値からの値の取り出しを同時に学んだほうが良いだろう。

つめこみすぎ

この章で学ぶ構文が多すぎる。パターンマッチを内包表記内で使う例はここでは雑音だ。その他、ガード、where節、let ... in ...式、case式などを1度につめこみすぎだ。

第4章 再帰

ジョークがやや不適切

「再帰が何なのかまだよく分からないなら、この段落をもう一度読んでください」は再帰的なジョークではなく「くりかえし」のジョークになっている気がする。正しくは「再帰とは『再帰』という言葉で表現されるものです」あたりか。

もっと例を挙げようよ

再帰関数の例は簡単なものを中心にもっとたくさん必要だ。標準ライブラリの関数の再定義は良いとは思うが。クイックソートの例は美しいがダメな例。当時としてはしかたないが。

第5章 高階関数

カリー化やセクションについて説明してあるのは良い。高階関数を実際に定義してみるのも良い。

zipWith, map, filter

これらの関数についてここで学ぶのは良いが、個人的な考えではこのような「基本的」な関数についてはまずは「使いかた」を学び、次にを「定義のしかた」を学ぶほうが良いかと思う。いくつかの例で「使いかた」を身につけたうえで、「ではその定義はどうなっているのか」という流れだ。

ラムダ式

ラムダ式、つまり無名関数をどこで扱うのかは難しい問題だ。より基本的なものとしてはじめのほうで扱う方法がひとつ、使用例を挙げるためにmap等の高階関数を学んでからがひとつ、だ。意図を明確にするために関数定義のときにラムダ式をうまく使うという示唆は非常に良い。

畳み込み

畳み込みの説明は良い。が、しかしこの説明の前に、生の再帰で同じものを定義する例を置いたほうが良いのでは。いきなりfoldl, foldrを出すのではなく、いくつかの再帰的な定義の例を挙げ、それらが同じ枠組みを持っていることを示し、そのうえでfoldl, foldrでまとめるといった形だ。

関数適用演算子

$(関数適用演算子)の説明は非常に良い。「はるか右に閉じ括弧のある開き括弧」という説明はさすがだ。

関数合成とポイントフリースタイル

ここらへんの説明は非常に良い。

第6章 モジュール

ここでモジュールについて説明するのは「しかたないか」といった感じだ。例を挙げるうえで標準的なモジュールを使いたくなるので。ただ、ここではまだimportの構文だけ導入する程度でも良いのでは。学習者は気を散らさずに「関数」に親しむことに集中したほうが良いと思う。

foldl'

関数foldl'についてはたしかにどこかで触れる必要がある。しかし、ここではなくてfoldlのところで触れたほうが良い。ただしfoldl'がPreludeに含まれていないためモジュールの説明を先にする必要があった。さきにimportのみにしぼって説明しておくべきだろう。

Data.Map

関数lookupを学んだらたしかにData.Mapに触れる必要がある。しかし「入門」ということで考えたならリストでの辞書にはパフォーマンスの面で問題があるということだけに触れておき、紹介するにしてもリファレンス程度にしておいたほうが良いかと思われる。まだ「代数的データ型」も学んでいないし。ここでData.Mapを扱うのは混乱のもとになるだろう。

第7章 型や型クラスを自分で作ろう

代数的データ型の章だ。これは大きなトピックのひとつだ。この位置にあるのは、まあまあ妥当だ。もうすこしリストを使っていろいろと遊んだあとでも良い気もするが、どっちもどっちといった感じか。

列挙型の例が欲しい

自分で定義する列挙型の例があったほうが良い気がする。また、newtypeで表現できるようなコンストラクタがひとつの例も欲しい。そして、その2つが矛盾なくひとつのdata構文で表現できるよというアハ体験が用意できるのでは。ちなみにnewtypeもいつかは紹介しなくてはならないが、導入が難しいな。

レコード構文

レコード構文はもうすこし後で扱ったほうが良い気がする。気が散りそうだ。便利だし紹介はしたい気もするが。

型引数

型引数の説明はまあまあ良いように思う。「データ型宣言に型クラス制約を付けないというとても強いコーディング規約」に触れているのは非常に非常に良い。

つめこみすぎ

この章はすこしつめこみすぎだ。インスタンスの自動生成、型シノニム、再帰的なデータ型、Functorなど。「実際に使う直前に」説明すれば良いものや、再帰的なデータ型やFunctorなど別に1章をとって説明すべきものなどが含まれている。

型の種についてはまだ説明しなくてもいいのではないだろうか。種そのものは、そんなに難しい話ではないので説明しても良いかもしれない。ファンクターの説明のあたりかな。

第8章 入出力

入出力(IO)をどこで説明するかはHaskellを教えるときの永遠のテーマだ。Hello, world!を表示するために最初に教えたいが、本当のことを知るには関数、代数的データ型、型クラス、モナド等々、いくつもの知識が必要で、むしろHello, world!の真相を知ったころにはHaskellの基本はほとんど学べたことになる。この書籍では中間をねらったようだ。モナドについて説明する前に「副作用の分離」という側面でIOを扱っている。個人的な考えではむしろ「副作用の分離」はIOモナドという本質的にクリーンな考えかたの副作用であると考えている。IOモナドという美しい抽象化をしたら結果として副作用が分離された、といった感じだ。

「入出力をさきに学びたい」という需要がどのくらいあるのかという話だ。他の言語を学んできた人達ならばそこまで入出力に飢えていないのではないだろうか。

僕ならばファンクターやモナドの考えかたに十分親しんでもらったあと、それとは関係なくIOマシンの結合のしかたを考えていき、あら不思議IOマシンはモナドの枠組みにおさまりますね、といった話にしたい。

第9章 入出力

8章と9章はHaskell自体を理解するには不要だ。たしかにHaskellで何か面白いことをするには入出力は必要だ。しかしHaskellの真髄を理解したうえでその土台のうえでこれらを学べば良いかと思う。Haskell初心者であってもプログラミング初心者ではない層を仮定すれば、あるいは完全なプログラミング初心者であれば、入出力をそんなにあせることはないかと思われる。

random, bytestring

randomとbytestringの話題は何かものを作るときに必要だ。Haskellの真髄を理解するには不要だ。だからHaskellを理解したあとに紹介するのが良いかと思われる。

10章 関数型問題解決法

道路網の例題はなかなか優れていると感じる。

詳細: 第11章から第14章まで

全体的に

ファンクターからアプリカティブへ、そしてモナドへと強力になっていく概念を説明し、そのうえでいくつかの一般的なモナドを説明している。これは非常に示唆的ではあるが、初心者にとってわかりやすい導入かどうかは疑問だ。むしろファンクターとモナドは別々の概念として説明したほうがわかりやすいと思う。そのうえで中級的な話題としてモナドは実はファンクター+joinだよという話をし、さらにファンクターとモナドとのあいだにアプリカティブがあり、そのアプリカティブによってアプリカティブスタイルでコードが書けるという説明をするといった感じか。

モノイドをこの流れで学習する必然性はないようにも思う。Writerモナドの説明には必要だけど。WriterモナドはとりあえずたとえばLoggerモナドとしてStringを使っておくとか。もっとモナドまで一直線のほうが初学者にはわかりやすいように思う。

第11章 ファンクターからアプリカティブへ

ファンクター

ここでIOや関数をファンクターの例として挙げるのはどうなのだろうか。もうすこし自作の型を作ったり練習したあとのほうが良さそうだ。

ファンクター則に触れているのは良い。法則を破ってみる例を挙げているのも実際に手を動かせるので良い。

アプリカティブ

はじめの導入のfmap (\f -> f 9) aの例はミスリーダブルだ。この例はないほうがわかりやすいように思う。

ちなみにミスリーダブルという言葉はない。多分。

(<*>)のすごさは以下のように考えるとよりはっきりするかも。f (a -> b -> c > d > e) -> f a -> f (b -> c -> d -> e)

本当ならファンクターにはなりうるけどアプリカティブにはなりえないデータ構造の例を挙げられるとわかりやすいのだけど、にわかには思いつかない。

ZipListについては「へー」という感じ。

アプリカティブ則について触れているのはとても良い。

sequenceAも良いと思うが入門には不要だ。

第12章 モノイド

もしもモノイドを教えるのならばもっと前、ファンクターよりも前で良いと思う。ここで教えるのはファンクター、アプリカティブ、モナドという流れの勢いをそぐ。

newtype

ここでnewtypeを教えるのはまあ良いような悪いようなといった感じ。訳注のGeneralizedNewtypeDerivingは良い。

newtypeと遅延評価の関係の説明は非常に良い。入門には不要だが、必ずどこかで学んでおいたほうが良い内容だ。

「Haskellは怒りを爆発させます(専門用語では例外を投げるともいいます)」のフレーズは好き。

モノイド

モノイド則が紹介されているのは良い。

Orderingがモノイドだって話は「おー」って感じだ。

Foldableは畳み込みをリストからより一般的なデータに拡張する。これも入門には必要ないだろう。けど、いつかは学んだほうが良さそうだ。ただし、こういった抽象化の動物園はいくら学んでもきりがないという面もある。

第13章 モナドがいっぱい

これは「ジブリがいっぱい」を意識してるのかな?

アプリカティブの強化

ファンクター、アプリカティブ、モナドのような順で理解していくのは、「モナドを理解する最も楽な道」ではない。ファンクターとモナドは別々に学んだほうがわかりやすいように僕は思う。以下の関係は確かにキャッチーだが、それは理解のしやすさとは関係ない。

fmap :: (a -> b) -> f a -> f b

(<*>) :: f (a -> b) -> f a -> f b

(=<<) :: (a -> m b) -> m a -> m b

さらにそれが本当にモナドの本質かと言えば、そのような抽象の網目は複雑でどちらの方向やどちらの経路がより本質的かという上下関係のようなものはない。たとえばArrowのほうからMonadのほうへいくことも可能だ。もちろん僕もArrowよりApplicativeのほうが好きだけど。

ただし7.10ではApplicativeの型クラス制約がつくこともある。どうしよっかな。アプリカティブは説明する必要がありそうだ。

綱渡りの例はまあまあ良いかな。

関数guardはMonadPlusが必要になる。リスト内包表記を説明するのならこれも必要かもしれない。

モナド則の説明は良い。

第14章 もうちょっとだけモナド

Writer、Reader、State、Errorモナドを紹介している。モナドを紹介するときにStateモナドをより具体的にしたものを例として出すとわかりやすいだろう。ここで差分リストを紹介しているが中級的な内容だ。

モナディック関数liftM, join, filterM, foldMを紹介している。関数joinのところはすこし面白い。

詳細: 第15章

zipperはひとつの手法として興味深いし便利だし使いたい。しかし入門的な話ではない。

詳細: 付録

Textの話とOverloadedStrings拡張の話、ViewPatterns拡張の話が出ている。それぞれ役には立つがとくに本質的な話ではない。

アマゾンでの評価

おおむね好評価だ。

pro

contra

ブログ

bleisさんの書評

attonさんの書評

keigoiさんの書評

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics