HackageでHaddockが生成されない時は

ここのところずっとHackageでHaddockの生成ボットが止まっているようで、新しくアップロードされたパッケージはたいていドキュメントが無い。どうも新しいサーバにHackageサーバを移しているようなのだけど、きっと忙しいんだろう。

自分で管理しているパッケージに関してはローカルでcabal haddockしたものをアップロードすることができるので、ここら辺を参考にすると幸せになれる。

上のページのhackagedocsはパスワードに特定の記号が含まれているとこけるので、URLエンコードする版を貼っておく。

あるパッケージのバージョンによって別のパッケージへの依存関係を変更する

具体的にはaesonのバージョンが新しい場合にのみscientificを依存関係に組み込みたいとする。

library
  build-depends:
    (aeson >= 0.3.2.5 && < 0.7.0) || (aeson >= 0.7.0 && scientific)

こんな感じにできないかなぁと思っていたが、これはparse errorになり動かない。同僚に聞いてみたところ、flagを使うのが定石らしい。

flag aeson070
  default: False
  manual: False

library
  if flag(aeson070)
    build-depends:
        aeson >= 0.7.0
      , scientific
  else
    build-depends:
     aeson >= 0.3.2.5 && < 0.7.0

aeson070という名前は何でも良い。なぜならmanual: Falseの場合*1、Cabalはaeson070 == Falseでインストールを試み、失敗した場合は自動的にaeson070 == Trueにして再度インストールしようとする。要するにユーザが手で指定するフラグでは無いので何でも良い。

*1:Falseがデフォルト値

hpc-coverallsでHaskellプロジェクトのテストカバレッジを可視化する

GHCには昔からHaskell Program Coverage (HPC)というカバレッジを計測する機能とツールがついてくるのだけど、コマンドラインオプションの指定が面倒だったり、そもそもHPCにバグがあって使いづらいためか、あまり広くは使われてこなかった。

ところが最近になって状況を一変させるかもしれない、hpc-coverallsというパッケージがHackageに上がっていることに気がついたので使ってみた。

Coveralls自体は広く使われてるので解説はいらないと思う。GitHubCoverage Statusみたいなバッジをよく見かけるはず。

hpc-coverallsの使い方は簡単で、Hackageのドキュメントにあるとおり

  • before_installでcabal install hpc-coveralls
  • cabal configureする時に、--enable-library-coverageをつける
  • cabal testの代わりにrun-cabal-testする
  • after_scriptでhpc-coveralls <テスト名>

とすれば良い。ただし、

  • hvr/multi-ghc-travisと併用する場合
    • cabalコマンドがcabal-1.18という名前なので、run-cabal-testする前に、パスが通っているところにln -s /usr/bin/cabal-1.18 /path/to/cabalする必要がある
  • パッケージの依存関係を満たせずにコケる場合
    • cabal install --only-dependenciesした直後に--avoid-reinstallsをつけてhpc-coverallsすると、自分のパッケージの依存関係を壊すことなくインストールできるかもしれない

あたりに気を付けると良い。influxdbとlifted-asyncで設定してみたので、設定例が見たい方はこちらをどうぞ。

実際に使い始めると、hpcコマンドを使うよりはるかに簡単で見やすいので、カバレッジを取りたいならおすすめ。hpc-markupのような1行の中でどこが実行されたかのような細かい情報までは取れないけど、よっぽど1行が長いのでなければ十分なんじゃないかと思う。

f:id:maoe:20140409171323p:plain
f:id:maoe:20140409171331p:plain
f:id:maoe:20140409171337p:plain

HaskellからInfluxDBを使う

Haskellからお手軽に時系列データベースにアクセスする必要が出てきたので、今巷で人気が出始めたInfluxDBのHaskellクライアントライブラリを書いた。

ドキュメントがあんまりなかったり、投げる例外が適当だったりするけど、ひとまず使えるようにはなっている。速度はあまり気にしないで書いたけど、困るほど遅くはないと思う。

公式リポジトリrandom_points.rbをベースに、いろいろ機能拡張したものがrandom-points.hsで、これらを見比べれば大体の使い方はわかるんじゃないかと思う。だいたいaesonのようなものと考えればいい。

Pattern synonymsの使い道

もうすぐ出る出ると言われ続けて久しいGHC 7.8は、大きめの新機能がいくつも入る。そのうちの一つがpattern synonymsという言語拡張で、これまで第一級市民でなかったパターンを、再利用可能な部品として扱えるようにする仕組み。チケットが登録されてから3年越しに実現された。

参考資料としては

あたりを読むと良い。

先日たまたまpattern synonymsのよい使いどころに遭遇したので紹介する。きっかけは


というツイートに対して、
と返ってきたのでOlegさんのList m aの使用例を元に書いてみたらpattern synonymsがちょうど良かったという流れ。

もとのOlegさんのコードと比べると、List m aの定義が異なっているのに、

pattern Nil = Pure ()
pattern Cons x mxs = Free (F x mxs)

という2つのpattern synonymsを使うことで、他の関数は(些末なスタイルの違いを除けば)まったく同じになっていることがわかる。ここから2つの利点が挙げられる。

  • 繰り返し出てくる複雑なパターンの簡略化
    • ここではFree (F x mxs)のようなネストしたパターンをCons x mxsと書ける。またこのpattern synonymsがbidirectionalなのでFree (F x mxs)という値もまたCons x mxsと書ける。
  • パターンマッチのインタフェースを保ったまま、データ型の内部表現を変更できる
    • 従来の代数的データ構造のみでは、パターンマッチするにはデータコンストラクタを公開する必要があった。これはつまりデータ構造を変更するとパターンマッチ部分も壊れることを意味する。先の例のList m aではOlegさんのコードからfreeを使ったコードに変えると、NilとConsを使うすべての関数が壊れてしまう。pattern synonymsを使えばこの問題は回避できる。データコンストラクタは非公開のまま、pattern synonymsだけを公開すればよい。

Pattern guardsやview patternsとの違い

GHCのパターンに関する言語拡張としてpattern guardsとview patternsというものもある。どちらもpattern synonymsとは別の機能で、特にview patternsはpattern synonymsと併用することもできる。

次のコードは同じ関数zipZagを言語拡張無し、pattern guards、view patterns、pattern synonymsを使って書いてみた。

{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq

-- No language extensions
zipZag :: Seq a -> Seq b -> Seq (a, b)
zipZag xxs yys =
  case Seq.viewl xxs of
    x Seq.:< xs -> case Seq.viewr yys of
      ys Seq.:> y -> (x, y) Seq.<| zipZag xs ys
      _ -> Seq.empty
    _ -> Seq.empty

-- Pattern guards
zipZag' :: Seq a -> Seq b -> Seq (a, b)
zipZag' xxs yys
  | x Seq.:< xs <- Seq.viewl xxs
  , ys Seq.:> y <- Seq.viewr yys = (x, y) Seq.<| zipZag' xs ys
  | otherwise = Seq.empty

-- View patterns
zipZag'' :: Seq a -> Seq b -> Seq (a, b)
zipZag'' (Seq.viewl -> x Seq.:< xs) (Seq.viewr -> ys Seq.:> y) =
  (x, y) Seq.<| zipZag'' xs ys
zipZag'' _ _ = Seq.empty 

-- Unidirectional pattern synonyms + view patterns
pattern Empty <- (Seq.viewl -> Seq.EmptyL)
pattern x :< xs <- (Seq.viewl -> x Seq.:< xs)
pattern xs :> x <- (Seq.viewr -> xs Seq.:> x)

zipZag''' :: Seq a -> Seq b -> Seq (a, b)
zipZag''' (x :< xs) (ys :> y) = (x, y) Seq.<| zipZag''' xs ys
zipZag''' _ _ = Seq.empty

pattern guardsもview patternsも、関数適用(ここではSeq.viewlとSeq.viewr)した後の結果の値に対してパターンマッチするコードを書きやすくする。一方、この例でpattern synonymsはunidirectionalでzipZag''とzipZag'''を比べてみればわかるように、単にパターンに別名を付けるために使われている。

pattern synonymsは、zipZag側が本当のデータ型に対してパターンマッチしているかのように書ける点がpattern guardsとview patternsだけを使った場合に対して優れている。

Re: Real World Haskellの古いところ

Real World Haskell の古いところ - あどけない話の25章と23章についてのコメントをまとめました。 > id:kazu-yamamotoさん











GitHubと連携するチャットサービスGitterが便利そう

普段使っていないメールボックスを覗いてみたら、Gitterからベータテストの招待状が届いていたので使ってみた。

f:id:maoe:20140117200918p:plain

使い方は簡単で、GitHubのOAuthでログインして自分のプロジェクト名をクリックするだけ。これでもうチャットルームが作られて、使えるようになる。

f:id:maoe:20140117202652p:plain

記法はGitHub flavouredなmarkdownが使える。GitHub Issuesとも連携しているので#と打つとissueの補完ができる。

f:id:maoe:20140117200929p:plain

さらにチャットルームの歯車アイコンからポチポチするだけでGitHub上でのコミットやコメント等の動きをチャットルームに流せる。.travis.ymlを弄ればTravis CIのビルド結果も流れるようになる。

f:id:maoe:20140117200925p:plain

この記事を書いている時点では

に対応している。詳しいドキュメントはまだ無いようなので、公式ブログを覗いてみるのがいいと思う。GitHub OAuthでどうして書きこみ権限が必要かの釈明も書いてある。

問題なのは、こんなに簡単にコミュニケーションツールがセットアップできても、肝心の人が集まるようなソフトウェアを書いてないことなので、まあぼちぼちがんばろう。