トップ 最新 追記

follow ikegami__ at http://twitter.com

イネムリネズミ日記

いけがみを召喚するには、出現予定を参考にしてください。三週間前までにメールをくだされば、日程を追加するなどしてスケジュールに組み込むことができるかもしれません。勉強会や個人的な会合、中途採用面接などに応じます。日記に書かないことはこちら

2003|04|05|06|07|11|12|
2004|01|02|03|04|05|06|07|10|11|
2005|01|02|03|04|05|06|07|08|11|
2006|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|11|12|
2010|03|04|12|
2011|02|03|04|06|08|09|10|

2010-12-08 Haskell Advent 2010 Day 3 [長年日記]

_ Haskell のプロジェクトを締めくくるとき

(このエントリはHaskell Advent Calendar jp 2010のために書かれました/その他のAdvent Calender)

プログラミング言語 Haskell学習したあと、最初にしてみたいことはなんでしょうか。 それはおそらく、「学習したかった理由」そのものです。 アプリケーションやライブラリを作ってみよう、ということが次の目的だと思うので、紹介します、ハマるところ一カ所も説明。

まず最初に知るべきことは Cabal です。 The Haskell Cabal - Common Architecture for Building Applications and Libraries という仕組みがあります。

Cabal はひとことでいうと、ポテトチップスの袋の裏です。 ポテトチップスの袋の表には、魅力的な写真や「コレ ハ いめーじ デス」といった目を惹くデザインが施されています。いっぽう、裏には「名称:ポテトチップス」とか、「賞味期限」「原材料名」などが記載されています。

ソフトウエアもまた、ポテトチップスの袋と同じような側面をもっています。 「どのようなことができるか(What)」「どのように使うか(How)」は、 作者が訴えたいことだと思いますが、これがポテトチップスの袋の表に対応します。しかし、それを使う(食べる)人にとっては他にも気になることがあるのです。想像してみてください。

Haskell でのプロジェクトをしめくくるとき、忘れてはいけないことが Cabal の記述、そしてインストーラ Setup.(l)hs の作成です。

_ Cabal の書き方

Cabal はテキストファイルです。 アプリケーションやライブラリに関するあれこれを Cabal のフォーマットで記述します。 テキストエディタで書くこともできますし、コマンドラインで対話的につくることもできます:

% cd your_project_directory
% cabal init
Package Name [default ...]? _
...

Cabal のマニュアル最新号と照らし合わせつつ、質問に答えましょう。はじめての方は、ある程度時間をとられることを覚悟してください。試行錯誤しながらすすめることになります。

上記に挙げた Cabal の書き方のなかに「darcs をつかう」ということがありますが、これは単なる布教活動です。信者を増やしたいのです。git など、その他お好きな VCS を使いましょう。

_ Cabal を書くうえで悩むこと

たくさんあります。そのなかでも、必ず直面する 3 つのことがらについて:

_ 1. プロジェクトの名前

名前重要。Cabal では パッケージの名前の仕様があらかじめ決められています。 特に大事なのは、ひらがな・カタカナ・漢字は使えない、ということです。残念。 世界の人がキーボードでこんにちはできるよう、英数字などを使いましょう。

すでにあるプロジェクトと名前が重なってしまうと後々困ることになるので、あらかじめ hackageDB :: [Package] を参照しましょう。

メイドや、まほろさんランカチャンなどはすでに実在します…

_ 2. バージョン番号

Haskell では、 パッケージのバージョン番号のポリシーが決まっています。したがいましょう。

_ 3. パッケージの依存関係

パッケージの依存関係を書かなければいけないのですが、これが簡単ではありません。ポルナレフ流に言うと

ありのまま 今 起こったことを話すぜ!

『おれが作ったパッケージをビルドしようとしたら いつのまにかビルドできなかった』

な…何を言っているのか わからねーと思うが

おれも何をされたのかわからなかった…

みたいなことが将来おこります。わけがわかりません…

ghc では、Haskell のライブラリにバージョン番号を振っています:

% ghc-pkg list
...
base-x.y.z
haskell98-x.y.z
unix-x.y.z
...

プログラムを書くと、なにげに import したライブラリは、 じつは様々に分けられたパッケージに含まれています。

気がついていなかったかもしれませんが、 たとえば Data.Listは base パッケージ、 Data.Map は containers パッケージに含まれています。 ふだんは、こうしたことを意識しないですむようになってますが、 Cabal を書くうえではパッケージ名とバージョンを知る必要があります。

パッケージを細分化する現在の仕組みは ghc 6.12.1 - Libraries から導入されました。また、ghc 6 と ghc 7 ではライブラリ機能の内部構造が変わっています。ghc 6.12.x より前の Haskell プログラマはパッケージシステムについて知らなければなりません。

データ型や関数などが、どのパッケージの、どのバージョンに含まれているか、ということが Cabal を書くうえで重要です。また、ghc は後方依存性よりも機能を優先する人々によって作られています。ので、将来のことはわかりません。パッケージのメンテナは、随時、依存するパッケージのバージョンを監視することになります…どんなプロジェクトであれ、パッケージの依存関係を記述しなければビルドすることはできません。

これは誰にとっても優しくない設計なのですが、 最近(というか今日) 状況が改善されました。

packdeps パッケージは、「バージョンの依存関係」を調べてくれるツールです。

具体的には、packdeps に用意されている関数を使います:

  1. loadPackage :: FilePath -> IO (Maybe DescInfo) で Cabal ファイルを読む
  2. loadNewest :: IO Newest で最新情報をゲット
  3. checkDeps :: Newest -> DescInfo -> (PackageName, Version, CheckDepsRes) で得られた結果を show

すればいいです。packdeps が ghc や Cabal に追いつかなくなると、これもダメになるのですが。

HackageDB に登録されたパッケージについては、Web インターフェイス Hackage Dependency Monitor で気楽に調べられます。

_ おわりに

Cabal について理解するべきことはたくさんあります。できるだけ書きたかったのですが、原因不明の疲れて気絶してしまう病にかかってしまい、自重しました。通院治療しています。

が、このエントリを書き上げることができたことは、大きな自信になりました。来年から体調を徐々に戻し、考えたことを書いていきたいです。

情報元の英文を日本語訳することも必要かもしれませんが、 情報は頻繁に更新されるので対応できません。原典をあたってください。 もし、日本語の情報が必要なら、継続して翻訳するためのチームをつくらないと。

Cabal を書くだけでなく、インストーラ Setup.(l)hs も書くことにより、 はじめて配布可能なパッケージになります。 実際に手を動かしてみると、そんなに手間のかかることはありません(パッケージの依存関係についてだけ面倒)。 多くの方がパッケージを公開して、 Haskell コミュニティを熱くしてくれることを望みます。Hackage DB に登録するには Hackage accountが必要になります。Cabal FAQの質問をクリックすると答がでます。最初から出してくれよ…(実は、質問のリストが上にあって、それぞれの回答が下にある)

サインにかえて @ikegami__

_ つけたし

執筆当時の最新 ghc 7.0.1 では cabal (0.8 以上必須)との協調が、 残念ながらうまくいっていないようです。これは、ghc 6 から 7 への変更で パッケージ管理のしくみが大きく変更したことと関係しています。 ときどき依存関係が壊れてしまい、ghc-pkg check で悲しい事態に陥ることがあります。 ghc 7 に移行するのは時期尚早だなと感じました。

しかし、カイゼンはものすごいスピードで進んでいるので、次の ghc がリリースされるのはすぐでしょう。奇数番の奇数番(x.y.zのxとzが奇数)は落とし穴がたくさんあり ghc-7.0.1 もそうです。落とし穴に落ちたら、 バグレポートを作るのがあるべき姿です。

この問題をとりあえず回避するには、今回紹介した packdeps で依存関係を調べ、cabal に引数 --constraint をつけて適切な情報を渡すことです。 --update-dependencies と合わせてつけたい。

こんなことをいちいちするのはばかばかしいので、cabal のほうが packdeps の仕組みを取り入れるに違いない、次のリリースを楽しみにしています。

_ 将来(2011年以降)の読者へ

Cabal の仕組みはどんどん変わります。ここに書いてある情報は古くなって意味のないものになるでしょう。Google it.

_ CM(それでも町は廻っている 1 (Blu-ray/DVD) 12/24 リリース)

イカ娘もいいゲソが、歩鳥ちゃんもかわいいポコ(原作も合わせて読むと吉)。 それでも町は廻っている(アニメ)/(原作)/原作第3巻14話を見ないと意味不明なクラシック応援サイト

Functional Ikamusume Advent Calendar jp 2010のネタはないです…イカ娘△


2010-12-09 3 日目だめやないか [長年日記]

_ Haskell Advent Calendar jp 2010(つづき)

参加順にってルールに書いてあるじゃないですか。ルールやで! ルール・ザ・ワールドやで!

23番目なので、ええと何日になるんですか、23 + 6 = 29 日…クリスマスはどこ

大掃除とか年賀状とかできない子なのに大丈夫かな、心配だ…が、それまで生存するという望みが。

ネタはあらためて考えます、たぶん。論文のほうが締切先なのに、逃避した天罰にちがいない、晴天さんすみません。


2010-12-29 Haskell Advent 2010 Day 23 [長年日記]

_ Pointfreeスタイルで書こう

2011-02-12 追記: 推敲したあたらしい文章を書きましたので参照ください。

(このエントリは Haskell Advent Calendar jp 2010 のために書かれました / その他のAdvent Calender)

pointfree という単語は聞き慣れないかもしれません。 幾何学(topology:トポロジー)が由来です。 Haskell は数学の言葉が大好きなので、数学アレルギーを簡単にひきおこします、こまったものだ…

f1 x = x + 1
f2   = (+ 1)
g1 x = 2 * x + 1
g2   = (1 +) . (2 *)

執筆中−せつめい、そして point とはなにかをいう、ここで。

つぎに Haskell Advent Calender 22日目に出てきた例も見てみましょう。

{-# LANGUAGE BangPatterns #-}
import Data.List ( foldl' )
  
sum1, sum2 :: Int → [Int] → Int
sum1 s []        = s
sum1 !s (x : xs) = sum1 (s + x) xs
sum2 = foldl' (+)

sum1sum2は、両方とも同じ意味を持つ関数です。 sum2は「write sum1 in point-free style」と 呼ばれます。日本語だと point-free スタイルで書く、と訳すのかな。 point-free は無理に和訳をつくる必要はないと思います。

point-free スタイルは、Haskell に慣れていない人が読みにくいと感じる一方で、 Haskell に慣れた人が好む書き方です。ということで、これも Haskell の壁(Haskell Advent day 7) になるのかもしれません。壁はよくないのでこわします。

point-free スタイルがわかりにくい理由は複数あります:

  • 型がわからない
  • 何がいいのかわからない
  • どうやって思いつくのかわからない

まだあったらすみません、聞いてください。

これらはみな ghci で解決することができます。まず、考えても型がわからないときは ghci の :type (短く :t) を使います。 :m は :module の省略形で、モジュールを読み込みます。

% ghci
> :m + Data.List
> :t foldl' (+)
foldl' (+) :: (Num a) => a -> [a] -> a
> :t foldl'
foldl' :: (a -> b -> a) -> a -> [b] -> a
> :t (+)
(+) :: (Num a) => a -> a -> a

foldl' (+)の型を理解するには、 Haskell の関数のカリー化と、部分適用についての知識が必要です。

(つづく)(清書中)


出現予定(召喚方法 ikegami@madscientist.jp):

RSS feed を再開しました。RSS の思想を尊重するために全文配信はしません、あしからず。