No Such Blog or Diary

«Prev || 1 | 2 | 3 | 4 | 5 || Next»

Literate Haskell (.lhs) での GHC プラグマ

普通の Haskell ソース(.hs) だと下のような {-# LANGUAGE ... #-} をファイルの頭に書くのだけど,.lhs でそのまま同じに書いといたら ghc が認識してくれなくて困った.

{-# LANGUAGE FlexibleInstances,MultiParamTypeClasses,FunctionalDependencies #-}

で,{- -} がコメントだから,コメントがデフォルトになってる Literate Haskell では # LANGUAGE ... # と書くのか? とかアホなことをしつつ,最終的にプラグマはプログラムの一部なんだから頭に > つけなきゃ認識されないよなとかいうことを理解した.

ということで,こう書けばよかった:

> {-# LANGUAGE FlexibleInstances,MultiParamTypeClasses,FunctionalDependencies #-}

今まで Literate Haskell でプラグマが必要なプログラムなんか書いてなかったのでアホなことに躓いた.

cabal install で依存関係のバージョン上限を外す:--allow-newer

Hackage は基本的に「テストしたバージョンまでで依存パッケージのバージョン上限を設けとけよ」的なノリなので,実際には問題ないんだけど上限よりも上のバージョンの依存パッケージしか入れられないから目的のパッケージがインストール出来ない,とかいう状況がチラホラある.バージョン上限を書き換えるためだけにデプロイやり直すのも作者が面倒だろうし.

んで,この状況にハマった時には目的のパッケージのソースを持ってきて手動でコンパイルするかとかやってたのだけど,cabal install のヘルプを良く見てみたら --allow-newer とかいう便利なオプションがあることに(今更ながら)気づいた.これつけとくとバージョン上限を無視してくれる.ほんと便利.

閑話休題.

cabal install を使った時とパッケージのソースで runghc Setup.hs configure とかやった時とでオプション無しの時の振る舞いが異なっていてハマった.cabal install がデフォルトでユーザ個別にパッケージをインストールをする(--user オプションがデフォルト?)のに対して,手元に持ってきたパッケージで runghc Setup.hs configure とかやった時にはグローバルにインストールされたものを探しに行っていた(--global オプションがデフォルト).おかげで入れたはずのパッケージが見つからないと怒られて,でも ghci で確かめると普通に import できて,何がおかしいのか暫く悩みまくった. runghc Setup.hs configure --verbose=3 とかやったら ghc-pkg を呼ぶときに --global をつけているのが見えて分かったのだけど,ここらのデフォルトの違いはどこから出てきたのやら.

今日のエラーメッセージ

Template Haskell でゴニョゴニョしてたら GHC がパニクった.

TTreeB.hs:69:3:ghc: panic! (the 'impossible' happened)
  (GHC version 7.2.2 for x86_64-unknown-linux):
	unknownNameSuggestErr UnhelpfulSpan
 
Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

まあ,生成したプログラムがおかしいんだろうけどデバッグめんどくさい……

RecordWildCards が便利だなぁ

Type class で可換半郡を次のように書いていた.

class CommutativeMonoid a where
    oplus :: a -> a -> a,  -- commutative, associative
    identity::a           -- the identity of oplus
data Bag a = Bag [a] deriving (Show,Ord,Read)
instance CommutativeMonoid (Bag a) where
  oplus (Bag a) (Bag b) = Bag (a ++ b)
  identity = Bag []

んで,type class だと不都合が生じたのでレコードで演算をまとめて持ち運ぶようにしたのだけど,定義部分に限っては RecordWildCards を使うとほとんど同じように書ける.演算の集合を定義するという点では type class でもレコードでも手間は大して変わらないっぽいねと. 楽だし簡潔でいい.

data CommutativeMonoid a = CommutativeMonoid {
    oplus :: a -> a -> a,  -- commutative, associative
    identity::a           -- the identity of oplus
    }
data Bag a = Bag [a] deriving (Show,Ord,Read)
bagMonoid = CommutativeMonoid { .. } where   
  oplus (Bag a) (Bag b) = Bag (a ++ b)
  identity = Bag []

インスタンス宣言に同じクラスの別のインスタンスを使う,例えば

instance (CommutativeMonoid a, Ord c) => CommutativeMonoid (Map c a) where
  oplus x y = unionWith oplus x y
  identity = empty

とかも

mapMonoid m = CommutativeMonoid { .. }  where
  oplus x y = let CommutativeMonoid {..} = m in unionWith oplus x y
  identity = empty

と書けばほとんど同じ雰囲気かね.let を内側で使ってあげるのが大事.下のようにやると定義の本体の oplus が新しく定義される oplus になっちゃうのでエラーを食らう.

mapMonoid (CommutativeMonoid {..}) = CommutativeMonoid { .. }  where
  oplus x y = unionWith oplus x y
  identity = empty

久々にHaskellでフィボナッチ数列の計算を書いてみた

とりあえず普通のHaskellプログラマが書くであろうフィボナッチ数列の計算:

fib = 1:1:[a + b | (a, b) <- zip fib (tail fib)]

Parallel List Comprehensions を使ってみた書き方:

fib = 1:1:[a + b | a <- fib | b <- tail fib]

Generalised (SQL-Like) List Comprehensionsを(無駄に)使った書き方:

fib = 1:1:[sum a | a <- fib, then group using (\b -> zipWith (\c d->[c,d]) b (tail b))]

こいつは -XTransformListComp で機能を有効する必要あり? とりあえず束縛時と使用時で変数 a の型が変わるのがまぎらわしい.ついでに using の後の関数の型が forall a. [a] -> [[a]] でないといけないのを時々忘れて怒られる.ついでに by をつけたときには forall a. (a -> t) -> [a] -> [[a]] でないと怒られる.第一引数の (a -> t) という型の部分には by の後に指定する式から作られる関数が渡されるので,そこでリストの要素を見て適当な型 t の要素に射影して,その結果を使ってリストの要素をリアレンジしても良いよと.でも,その関数以外ではリストの要素に触れてはいけないよと(forall がついてるから).むずい.

さらに -XViewPatterns を有効にして無駄に分かりにくい書き方をしてみる.機能の無駄遣い.

fib = 1:1:[sum a | a <- fib, then group using (\c@(tail->b)-> zipWith (\((:[])->c) d -> d:c) c b)]

とりあえず,変なプログラムを書いたおかげで Generalised (SQL-Like) List Comprehensions の使い方が分かった(元論文はだいぶ前に読んであったのだけど).

久々にHaskellでフィボナッチ数を計算する関数を書いてみた

fib((-1+)->n@((-1+)->m))|m<0=1|((,,fib n)m->(fib->x,_,y))<-()=x+y

ViewPatterns, PatternGuards, TupleSections の拡張機能を使ってみたかっただけともいう.

View patterns はパターン部分に計算を書けるしそれを連ねることもできるので(関数結合と逆向きだけど),なんとなくモナド(のbind演算子)でプログラムを書いている気分を味わえる気がする.Pattern guards はまあ面白い使い方がまだ思いつかない.Tuple sections は場合により便利だけど変なプログラムを書くのには使いにくいかも? λ式にも view patterns 書けるので,かっこを使いまくりな id 関数とか:

i=(\((,)() -> ((),x)) -> x)

ついでなので階乗を求める関数も.

fact n|1>n=1|((-1+)->fact->x)<-n=n*x
«Prev || 1 | 2 | 3 | 4 | 5 || Next»
Search
Feeds

Page Top