Subscribed unsubscribe Subscribe Subscribe

Re: Haskellの勉強で詰まってる部分

mizchi.hatenablog.com

Haskellを習得する上で難しいポイントだと思います。大きく分けると次の二つにまとめられるのではないかと思います。

  • コードの中で現れる識別子からそれが何なのかを探しづらい
  • Cabalがつらい

それぞれ個人的な見解を書いてみます。

コード中の識別子の探し方

モナドのところの

<$> とか <*> とか、え〜どっちがApplicativeで何がFunctorだっけ、そもそもその定義はなんだったっけ。え〜あ〜〜〜みたいになる。

名前空間

そして名前で役割を推測することが困難な事が多々ある。mapM_ とか、前述した演算子とか。いや mapM_map があって mapM があって、っていう段階があるのは理解しているけど、ソース読んでて突然出現するそれには全く対応できない。

はどちらも識別子から型がわかれば大部分が解決します。ありがたいことに近年はghc-modをベースにしたサポートを各エディタから利用できます。EmacsVimはもちろん、SublimeではSublime HaskellAtomでもide-haskellを使えば、カーソル下の識別子の型を簡単に確認できるようになります。あとはhasktagsなどでタグジャンプできるようにしておくのもよいと思います。

これに加えてHoogleHayoo!演算子の検索も充実しているので役に立ちます。

プロダクションでは qualified as するのが当たり前なのか徹底的に import Foo (bar)みたいに絞るのか、それすらわからない(後者のような気はしているが)。

これに関しては結構意見が分かれるかもしれません。すべてqualified importすべしという過激意見もありますが、タイプ量がだいぶ増える上にqualifyされた演算子はお世辞にも読みやすいとはいえません。

またすべての識別子を明示してimportするのもimportリストの管理が煩雑になりますし、80桁に押さえようとするとimportリストが複数行にまたがるようになって、ただでさえ長くなりがちなリストがどんどん長くなります。

個人的には

  • いつもimportする定番のモジュールは何も明示せずqualifyもせずにimport
  • 巨大なモジュールの一部のみ利用する場合は明示してimport
  • qualified importを前手に作られた、ほかのモジュールと衝突するようなモジュールはqualified import
    • Data.Text Data.ByteString etc...

みたいな感じで運用しています。ちなみに、少し話題がずれますがコードベースが巨大になってくるとimportリストよりexportリストをちゃんと管理することが重要で、モジュール内の何を外に見せて何を隠すかをよく考えることが肝心です。

Cabalつらい問題

sandboxが導入されてからはある程度過去の問題になりつつあると思います。cabalにはsandboxを強制onにするオプションがあるので必要なら使うとよいと思います。~/.cabal/configに

require-sandbox: True

と書くことで有効にできます。

あと、cabalファイルの書式はtoml形式ではないのでtomlのことは忘れましょう。独自形式です。

sandboxを利用しているのであれば、--force-reinstallsしない限りいわゆるcabal hellが起こることほとんどないと思います。ただしHaskell Platformを入れていてHPで提供されているパッケージの新しい版をインストールしたり、GHCのブートパッケージのバージョンを変えようとするとつらいことはあるかもしれません。

Cabalのつらさは皆痛いほど経験してきているので、Stackageという人力で安定しているパッケージセットを作るという涙ぐましい努力が行われています。これを利用するのも一つの手でしょう。