GHC 7.4.1 がリリースされました。
http://www.haskell.org/ghc/download_ghc_7_4_1
http://www.haskell.org/pipermail/glasgow-haskell-users/2012-February/021764.html
何度か知らせているように、GHC 7.2.x は "technology preview" という扱いだったので、今回がいつもの定期リリースになります。GHC 7.2.x 以降の機能や改良が必要で 7.2.x を使っているという方は、"technology preview" の 7.2.x から 7.4.1 にアップグレードした方が良いでしょう。
ただし、いつもの注意になりますが、GHC は一般ユーザー向けのリリースではありません。GHC 7.2.x 及び 7.4.1 の新機能や改良がどうしても必要だというのでなければ、一般ユーザーの皆さんは5月に Haskell Platform がリリースされるまで待って下さい。
* GHCi 上で型や型クラス、型クラスのインスタンスなどを宣言可能に
これまで GHCi 上では let 式を使って関数や変数を宣言することしかできませんでしたが、新たに型や型クラス、型クラスのインスタンスなどを宣言することができるようになりました。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/interactive-evaluation.html#ghci-decls
GHCi の複数行に渡る定義を行う機能と組み合わせて使うことで、よりソースコード上での定義に近い感覚で GHCi 上での定義を試してみることができるでしょう。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/interactive-evaluation.html#ghci-multiline
Prelude> :{
Prelude| data Nat = Zero | Succ Nat
Prelude| deriving Show
Prelude| :}
Prelude> Zero
Zero
Prelude> Succ (Succ (Zero))
Succ (Succ Zero)
あるいは
Prelude> :set +m
Prelude> class (Eq a, Show a) => Cmp a where
Prelude| cmp :: a -> a -> Bool
Prelude|
Prelude> :set +m
Prelude> instance Cmp Int where
Prelude| cmp = (==)
Prelude|
Prelude> cmp (33::Int) 33
True
Prelude> cmp (33::Int) 44
False
あるいは(後で説明する ConstraintKinds を使った例)
Prelude> :set -XConstraintKinds
Prelude> type Mappable = Functor
Prelude> type Controlable = Monad
Prelude> :set +m
Prelude> let mapC :: Controlable m => (a -> m b) -> [a] -> m [b]
Prelude| mapC = mapM
Prelude|
Prelude> :m Control.Monad
Prelude Control.Monad> void $ mapC print [1..3]
1
2
3
* :kind! で、型族の評価結果を表示できるように
GHCi の :kind コマンドに、型族を型に適用した結果を表示するための ! というフラグが追加されました。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/ghci-commands.html
例1(記述を簡潔にするために、後で説明する DataKinds を使っています):
{-# LANGUAGE TypeFamilies, DataKinds #-}
module KindTest1 where
data Nat = Zero | Succ (Nat)
type One = Succ Zero
type Two = Succ One
type family Plus (x::Nat) (y::Nat) :: Nat
type instance Plus Zero n = n
type instance Plus (Succ n) m = Succ (Plus n m)
*KindTest1> :kind Plus One Two
Plus One Two :: Nat
*KindTest1> :kind! Plus One Two
Plus One Two :: Nat
= Succ (Succ (Succ 'Zero))
*KindTest1> :kind! Plus Two One
Plus Two One :: Nat
= Succ (Succ (Succ 'Zero))
例2(後で説明する ConstraintKinds や PolyKinds を使った例):
{-# LANGUAGE ConstraintKinds, TypeFamilies, PolyKinds #-}
module KindTest2 where
import Data.ByteString (ByteString)
import Data.Traversable (Traversable(..))
import GHC.Exts (Constraint)
-- type Cmp a = (Eq a, Show a)
type family Listable t :: Constraint
type instance Listable [] = Traversable []
type instance Listable ByteString = ()
-- See also: http://ideone.com/UNLvM
*KindTest2> :kind Listable []
Listable [] :: Constraint
*KindTest2> :kind! Listable []
Listable [] :: Constraint
= Traversable []
*KindTest2> :kind! Listable ByteString
Listable ByteString :: Constraint
= ()
なお、:type コマンドを使った場合の型の表示に関しては、GHC 7.0.1 時の型検査器の書き換えで多少改善されています。例えば、
http://www.sampou.org/cgi-bin/w3ml.cgi/haskell-jp/msg/305
の例では、きちんと S (S (S Z)) を表示できるようになっています。
$ ghci Test.hs
GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help
(snip)
[1 of 1] Compiling Main ( Test.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t one `plus` two
one `plus` two :: S (S (S Z))
* 内部的な時間として、必ず実際の経過時間(wall-clock time)を使うように変更
これまでマルチスレッド版 RTS 以外では CPU 時間を「性能測定やプロファイル機能など GHC の時間を必要とする機能」で利用していましたが、プロファイル機能で正確に時間を測れないと言う問題があったため、必ず実際の経過時間を使うように変更されました。
http://hackage.haskell.org/trac/ghc/ticket/5282
http://www.haskell.org/pipermail/cvs-ghc/2011-November/068500.html
* GHC の性能測定機能の改良
GHC の性能測定機能に、プログラム実行中の情報を取得するための -T オプションが追加されました。他のオプションとは異なり、-T オプションでは結果をそのまま標準エラーやファイルには出力しません。代わりに GHC.Stats モジュールの関数を使って、プロフラム中で情報を取得する必要があります。以下のコラムで -T オプションの使用例を示しましたので、参考にしてみてください。
http://itpro.nikkeibp.co.jp/article/COLUMN/20110906/368177/?ST=ittrend&mkjt&P=5
* GHC のプロファイル機能の改良
GHC のプロファイル機能が HPC などと統合されて,大きく改良されました。この結果プロファイル機能利用時の性能が向上した他、幾つかの機能の改良が行われました。また、-auto* や -caf-all といったプロファイル機能で利用するコスト集約点を指定するオプションの名前が,何をするかをより分かり易く示した -fprof-* といったオプション名に変更されました。
http://www.haskell.org/wikiupload/9/9f/HIW2011-Talk-Marlow.pdf
http://www.haskell.org/pipermail/cvs-ghc/2011-November/067428.html
** スタックトレースの提供
GHC のプロファイル機能を使って、スタックトレースを行えるようになりました。
もちろん、以前からプログラムをプロファイル向けにビルドした場合には、RTS の -xc オプションを付けてプロフラムを実行することで、コスト集約点を下に実行時エラーの発生個所に関する情報を出力させることはできました。ですが、提供されるエラー情報はそんなに分かり易いものではありませんでした。
改良前:
http://www.kotha.net/ghcguide_ja/7.2.2/runtime-control.html#rts-options-debugging
この機能が改良され、RTS の -xc オプションで、エラー発生個所のスタックトレースを出力できるようになりました。
改良後:
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/runtime-control.html#rts-options-debugging
また、スタックトレース向けに,関数呼び出しの部分にコスト集約点を指定する -fprof-auto-calls オプションが新しく提供されました。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/prof-compiler-options.html
なお、スタックトレースの機能の提供する情報は RTS の -xc オプションからだけではなく,Debug.Trace モジュールに追加された traceStack 関数を使って出力させることもできます。
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/base-4.5.0.0/Debug-Trace.html
実際、プロファイルオプション付きでビルドされた GHC では、traceStack 関数の内部実装に利用されている関数を使ってスタックトレースを出力できるようにしているそうです。
http://www.haskell.org/pipermail/cvs-ghc/2011-November/068701.html
** プロファイル機能の並列プログラム対応
これまでプロファイル機能とマルチスレッド版(-threaded 版)RTSを利用してビルドした Haskell プログラムは、(RTS の -N1 オプションを指定するなどした)単一 CPU 上での実行のみしか対応していませんでした。ですが、GHC 7.4.1 から,(-N2 以上を指定するなどした)複数 CPU 上での実行にも使えるようになりました。
http://itpro.nikkeibp.co.jp/article/COLUMN/20110906/368177/?ST=ittrend&mkjb&P=2
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/prof-threaded.html
http://www.haskell.org/pipermail/cvs-ghc/2011-November/068646.html
ただし、現時点での実装では、コスト集約点を表現するデータ構造内の「メモリの使用量(allocation)」と「処理の呼び出し(entries)」を表現する部分が各 CPU で共有されるようになっていて、これがプロファイル対象の並列プログラムの性能を大きく低下させてしまうという問題があります。allocationは兎も角、entriesは実行時間の計測に関わるため、これでは各コスト集約点での実行時間の計測が正しく行えません。そこで、現時点では並列プログラムの性能を測定する場合,プロファイル向けにプログラムをビルドする際に -prof オプションと共に-fno-prof-count-entries オプションを使ってコスト集約点の entries を無効にすることを推奨するそうです。
なお、このプロファイル機能だけでは並列プログラムの振る舞いについて知ることはできないので、並列プログラムの性能について考える場合には並列プロファイル機能と併用することをおすすめします。
* 並列プロファイル機能の改良
GHC の並列プロファイル機能が改良され、並列 Haskell の spark に対する情報を出力できるようになった他、特定のイベント情報のみを選んで出力させることができるようになりました。
GHC 7.4.1 の並列プロファイル機能については連載の第49回の中で説明しましたので、詳しくはそちらを参考にしてください。
http://itpro.nikkeibp.co.jp/article/COLUMN/20110906/368177/
この記事以降の変更として、traceEvent 関数と IO モナド版の traceEventIO 関数が、Debug.Trace モジュールで公開されるように変更されています。また、traceEvent 関数と traceEventIO 関数を有効化・無効化するための u という修飾フラグが追加されています。
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/base-4.5.0.0/Debug-Trace.html#g:2
http://www.haskell.org/pipermail/cvs-ghc/2011-October/067200.html
他には以下にある ThreadScope のチュートリアルも参考になると思います。
http://www.haskell.org/haskellwiki/ThreadScope_Tour
* Constraint Kinds
型クラスなどを使った型の制約に別名を付けたり、型の制約を型族の対象として扱うための ConstraintKinds という言語拡張が加わりました。この言語拡張では型の制約を Constraint という種を持つ型として扱うことで、従来の type というキーワードを使って「型の制約に別名を付けたり、型の制約を型族の対象として扱う」ことを可能にします。
詳しくはこちらの記事を参照してください。
http://blog.omega-prime.co.uk/?p=127
なお、Contraint という種は ConstraintKinds という言語拡張を有効にするだけでは利用できません。Constraint という種を利用するためには、別途 GHC.Exts モジュールからインポートする必要があります。
* DataKinds と PolyKinds
データ型を型レベルに昇格(値を型、型を種に昇格)させるための DataKinds という言語拡張が加わりました。データ型を型レベルに昇格させる機能が入ったことで、値レベルのプログラムに近いより直接的な形で型レベルのプログラムを定義したり、引数の数のみを制約とした従来の種よりも適切な種の制約を持たせることができるようになります。
ただし、ユーザーが定義可能なデータ型を型レベルに昇格させることができるだけで、Int や Char,String のような組み込みのデータ型を型レベルに昇格させて扱うための機能は実装されていません。(type-nats branch で既に、数値リテラルを型レベルに昇格させたり,文字列リテラルを型レベルに昇格させたりする機能の実装が始まっています。次の GHC 7.6.1 ではこうした機能が使えるようになるかもしれません。)
また,多相的な種を扱うための PolyKinds という言語拡張が加わりました。ただし,今のところ多相的な種も GHC に推論させることができるだけで、ある型変数を多相的な種として宣言するための機能はまだ実装されていません。
このように DataKinds や PolyKinds 共に実装されたばかりで,機能にはまだまだ多くの制限があります。また,これらの機能の細部は今後変更される可能性があります。以下のページに今後 DataKinds や PolyKinds をどう改良していくかについて記したメモがありますので,詳しくはそちらを参照してください。
http://hackage.haskell.org/trac/ghc/wiki/GhcKinds
このようにまだまだ安定しない機能ではありますが、GHC での今後の型レベルプログラミングの動向が気になる方は是非試してみると良いでしょう。DataKinds や PolyKinds 言語拡張を使ったプログラムの例がいくつかこちらにありますので、試す際には参考にしてみてください。
https://github.com/ia0/GhcKindsExamples
* SPECIALISE 指示文の段階制御対応
SPECIALISE 指示文を段階制御の対象とすることができるようになりました。この機能は非効率的だった ^ 演算子の性能を向上させるために、必要になったものだそうです。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/pragmas.html#specialize-pragma
http://hackage.haskell.org/trac/ghc/ticket/5237#comment:16
* NOUNPACK 指示文の追加
-funbox-strict-fields オプションでは、UNPACK 指示文と同様に、「データ構成子の正格なフィールドに、値を非ボックス化した形で保持する」最適化を試みます。ですが -funbox-strict-fields オプションで行われる非ボックス化の中には実際の性能向上には寄与せず、何でも非ボックス化しようとしてしまうことで逆に性能を低下させてしまうものもあります。
http://hackage.haskell.org/trac/ghc/ticket/2338
そこでこの問題を解決するために、-funbox-strict-fields オプションを使っても決して非ボックス化の対象としない為の NOUNPACK 指示文が追加されました。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/pragmas.html#nounpack-pragma
* プログラムを実行するのに利用する CPU 数を変更するための setNumCapabilities 関数
GHC.Conc モジュールに、新しく Haskell プログラムを実行している最中に、Haskell プログラムを実行する CPU 数を変更するための setNumCapabilities 関数が追加されました。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/using-smp.html#parallel-options
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/base-4.5.0.0/GHC-Conc.html#v:setNumCapabilities
これにより、RTS の -Nxオプションを使わなくても、プログラマーの望んだ形で Haskell プログラムを実行するための CPU 数を指定することができるようになります。
ただし、GHC 7.4.1 の setNumCapabilities 関数では実行に使う CPU 数を増やすことはできても、減らすことはできない点に注意して下さい。
(HEAD には既に減らすための機能が入っているため、GHC 7.6.1 では CPU 数を減らすことができるようになる予定です。
http://www.haskell.org/pipermail/cvs-ghc/2011-December/069032.html
https://plus.google.com/107890464054636586545/posts/GsfcJfdkEYL )
また、setNumCapablities 関数で実際のマシンにある以上の CPU を指定してしまうと、プログラムの動作が遅くなってしまう可能性があります。そこで GHC.Conc モジュールでは、マシンの持つ CPU コア数を得るための getNumProcessors 関数を別途提供しています。
(ハイパースレッディングに対応した CPU nの場合、ハイパースレッディングによって提供される論理的なコア数になります。また、-threaded ではない RTS 上では CPU コア数は常に1になります。
http://www.haskell.org/pipermail/cvs-libraries/2011-December/014715.html
http://www.haskell.org/pipermail/cvs-ghc/2011-December/068858.html )
Prelude Control.Concurrent GHC.Conc> getNumCapabilities
1
Prelude Control.Concurrent GHC.Conc> getNumProcessors
8
Prelude Control.Concurrent GHC.Conc> setNumCapabilities it
Prelude Control.Concurrent GHC.Conc> getNumCapabilities
8
* 文字コード対応の強化
一部は GHC 7.2.1 で入った変更ですが、文字コード対応が大きく強化され、パス名や FFI での CString 型の呼び出しなどでも Unicode 文字列を扱えるようになりました。GHC 7.4.1 での文字コード扱いについては以下にまとめておきましたので、詳しく知りたい方はそちらも参考にしてください。
http://page.freett.com/shelarcy/log/2011/diary_12.html#ghc7_4_1_s_japanese_string_support
なお、GHC 7.2.1 から Unicode 6.0 に対応していますので、Unicode 6.0 の文字を表示できる環境であればこれらも利用できると思います。
http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/release-7-2-1.html#id567292
* Num クラスの変更
Num クラスから Show クラスと Eq クラスをスーパークラスとする制約が取り除かれました。このため、Eq クラスと SHow クラスの文脈が必要なコードには、Num クラスだけではなくこれらの型クラスも文脈とする必要があります。注意して下さい。
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/base-4.5.0.0/src/GHC-Num.html#Num
* ビット数を数えるための popCount メソッド
Data.Bits モジュールの Bits クラスに popCount メソッドが追加されました。更に x86(および x86_64)環境では、SSE 4.2 の命令を使ったコードを生成するための -msse4.2 オプション付けてプログラムをコンパイルすることで、この popCount メソッドを使った処理から POPCNT 命令を使った高速なコードを生成できるようになっています。(POPCNT 命令は正確には SSE 4.2 の仕様には含まれていないのですが、諸事情から SSE 4.2 扱いになっています。)
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/base-4.5.0.0/Data-Bits.html#v:popCount
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/options-platform.html
https://github.com/ghc/ghc/commit/2d0438f329ac153f9e59155f405d27fac0c43d65
http://www.haskell.org/pipermail/cvs-libraries/2011-August/014256.html
http://en.wikipedia.org/wiki/SSE4#POPCNT_and_LZCNT
* binary パッケージの追加
隠しパッケージ扱いではありますが、GHC の一部として (ユーザーに使わせないことを前提とした ghc-binary ではなく) binary パッケージが提供されるようになっています。GHC 7.2.1 リリース時の変更でしたが説明してなかったので、念のため。
* unix パッケージへの System.Posix.ByteString モジュールの追加
unix パッケージに、パス名を文字列の別名である FilePath ではなく、ByteString の別名である RawFilePath として扱う、System.Poix.ByteString および、System.Posix.*.ByteString モジュールが追加されました。
RawFilePath では、(GHC 7.2.1 で対応した)Unicode 文字列を含んだパス名を扱えない変わりに、ByteString を使ったパス名への高速なアクセスを提供します。
残念ながら Win32 パッケージや dierectory パッケージには対応するモジュールは提供されていませんし、GHC に含まれない Text は扱えませんが将来的にはこうしたものにも対応すると良いですね。(Text への対応は、GHC ではなく Haskell Platform が適当かもしれませんが。)
* qAddDependentFile メソッド
Template Haskell では、コンパイル時に I/O が扱えるため、ファイルを読み込んでコンパイル時に評価することができます。ですが、そうして読み込んだ外部ファイルは再コンパイルするかどうかのチェックの対象にできず、外部ファイルのみ変更されても再コンパイルの対象にならないという問題がありました。
http://hackage.haskell.org/trac/ghc/wiki/DependencyTracking
この問題を解決するため、Language.Haskell.TH.Syntax モジュールに外部ファイルの変更チェックを行う addDependetFile 関数が、Quasi クラスに addDependetFile 関数をメソッド化した qAddDependentFile メソッドが追加されました。(また、#icnlude でも同様の仕組みを使ってファイルの変更を確かめることができるようになっています。)
http://www.haskell.org/pipermail/cvs-ghc/2011-November/067592.html
http://www.haskell.org/pipermail/cvs-libraries/2011-November/014575.html
ただし、 ghc -M は Template Haskell を実行しないため、ghc -M から出力される Makefile には addDependentFile で指定した依存ファイルの情報が含まれないという制限があるそうです。
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/template-haskell-2.7.0.0/Language-Haskell-TH-Syntax.html#v:addDependentFile
http://hackage.haskell.org/trac/ghc/ticket/4900#comment
* 各パッケージの Safe Haskell 対応
GHC の提供する各パッケージで、Safe Haskell で安全に利用できることを保証した Safe や Trustworthy の付いたモジュールや、逆に安全でないことを示した Unsafe の付いたモジュールを提供するようになりました。
* http://www.haskell.org/ghc/docs/7.4.1/html/libraries/index.html
* http://www.haskell.org/ghc/docs/7.4.1/html/libraries/pretty-1.1.1.0/src/Text-PrettyPrint.html
安全な API と安全ではない API のある array パッケージでは、安全な API のみ提供する *.Safe モジュールと、安全でない API を提供する *.Unsafe モジュールが提供されるようになっています。
http://www.haskell.org/ghc/docs/7.4.1/html/libraries/array-0.4.0.0/index.html
また、今回のリリースには含まれませんが、vector パッケージでも Trustworthy を使って安全性を保証した *.Safe モジュールを提供するようになっています。
http://hackage.haskell.org/packages/archive/vector/0.9.1/doc/html/src/Data-Vector-Generic-Safe.html
目につく変更はこのくらいでしょうか? 全ての変更点についていちいち挙げていくときりがないので、その他の変更について興味のある方はリリースノートやマニュアル内の記述などを参考にしてください。
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/release-7-4-1.html#id567292
また、"technology preview" だった GHC 7.2.1 での新機能に興味のある方は、GHC 7.2.1 リリース時に送ったメールや、GHC 7.2.1 のリリースノートなどを見てみるのも良いと思います。
http://groups.google.com/group/haskell-jp/browse_thread/thread/8bd11025ccdc152d
http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/release-7-2-1.html
ただし、Safe Haskell とモナド内包表記の機能は GHC 7.4.1 で多少変更されています。混乱を避ける為にも、これらの機能について興味がある場合には GHC 7.2.1 での説明よりも GHC 7.4.1 のマニュアルでの説明を見た方が良いと思います。(また、GHC 7.2.1 頃に書かれた説明を読む場合には、単に読むだけではなく、実際に試して GHC 7.4.1 との違いを確認した方が良いでしょう。)
--
shelarcy <shelarcy hotmail.co.jp>
http://page.freett.com/shelarcy/
あっ、GHC 7.4.1 では隠しパッケージ扱いではなくなってますね。
訂正のついでに、GHC 7.2.1 リリース時に入った MonoLocalBinds の変更について書いておきます。
* MonoLocalBinds の変更
GADTs や型族を利用した場合に有効になる MonoLocalBinds ですが、
http://www.sampou.org/cgi-bin/w3ml.cgi/haskell-jp/msg/585
http://groups.google.com/group/haskell-jp/msg/3ac9b20d811eb77e
GHC 7.2.1 リリース時に制限が緩和されました。型宣言をつけなくても、「let や where で定義した関数や変数の定義に自由変数が使われていない場合や、定義に使われている自由変数が全て closed な場合」には多相的に推論されるようになっています(どういう場合に自由変数が closed になるかは、リンク先にある解説を見て下さい。)
http://hackage.haskell.org/trac/ghc/blog/LetGeneralisationInGhc7#Whichbindingsareaffected