読者です 読者をやめる 読者になる 読者になる

GHC 8.0.1/base-4.9.0.0の新機能まとめ

GHC 8.0.1は、最上位の桁が変わるだけあって、かなり新しい機能が追加されている。

base-4.9.0.0

めっちゃインスタンスが増えた

ghc/changelog.md at ghc-8.0 · ghc/ghc · GitHubを参照。あるべきインスタンスが存在することにより、孤児インスタンスを定義する必要がなくなるため、ぐっとストレスが減る。Monoid a => Monad ((,) a)Traversable ZipListなど、いくつかは私がやった。

Semigroup

ついにData.Semigroupが追加された。将来的にはこれはモノイドのスーパークラスになる。この変更によって、よりリーズナブルな定義ができるということも少なくないはずだ。

ベーシックな型が充実

Compose, Product, Sum, NonEmptyなど、決して利用頻度が高くないとはいえ基礎的かつ重要な型が追加された。種多相になっているので型レベルプログラミングフリークにとっても嬉しい。

MonadFail

ついにfailMonadから切り離された。もはやMonadには一片の羞恥もない。

この変更のため、いくつかの警告や言語拡張が追加された*1

Applicativeへの一般化

forever, filterM, mapAndUnzipM, zipWithM, zipWithM_, replicateM, replicateM_, traceM, traceShowMMonadからApplicativeへと一般化された。痒い所に手が届くようになるだろう。しかし、(*>)(>>)より効率の悪い実装になっていると深刻なダメージになりうるため、Applicativeのインスタンスにはより関心を向けなければならない。

ApplicativeDo

ApplicativeDo拡張を有効にすると、以下のコードをf <$> foo <*> barのようにしてくれる。

do
  x <- foo
  y <- bar
  return (f x y)

MonadよりApplicativeのほうが効率のよいような構造(クラシカルFRPにおけるBehaviorなど)では大いに役立つ。

Strict / StrictData

StrictDataを有効にすると、データ型のフィールドにデフォルトで正格フラグが付与される。アプリケーションを書くうえでフィールドを遅延評価させたい場面は少なく、いちいち!(……)と書く手間がなくなるため非常に有用だ。これをずっと待ち焦がれていた。

Strictを有効にすると、さらにありとあらゆる束縛が正格評価になる。やりすぎな気がしなくもないが、案外実用上は問題ないかもしれない。

TypeError

GHC.TypeLitsにGHC.TypeLits.TypeErrorが追加された。type family TypeError (msg :: ErrorMessage) :: kなる型族で、これを使うと型エラーを作れる。型レベルプログラミングがさらに楽しくなるだろう。

OverloadedLabels

IsLabelというクラスが追加された。

class IsLabel (x :: Symbol) a where
  fromLabel :: Proxy# x -> a

OverloadedLabels拡張を有効にすると、#foo(fromLabel @"x" @alpha proxy#) (fromLabel (Proxy :: Proxy "x")のようなもの)の構文糖衣になる。これにより多相なアクセサを定義できる可能性が生まれたが、非常に残念ながら型クラスの性質上van Laarhoven lens(lensパッケージのLens)にはできない。非常に残念だ。

GenericsのMeta

GHC.GenericsMetaというが追加され、型定義のメタデータを表すM1のパラメータとして与えられる。

data Meta = MetaData Symbol Symbol Symbol Bool
          | MetaCons Symbol FixityI Bool
          | MetaSel  (Maybe Symbol)
                     SourceUnpackedness SourceStrictness DecidedStrictness

Genericsでフィールドやコンストラクタ名を扱うのは骨の折れる仕事だが、これのおかげでいくらか楽になるに違いない。

種の同一性

種の同一性がきちんと扱われるようになった。これによりGADTの型レベルへの昇格や、種族の定義が可能になる。

型族のワイルドカード

type family Tail (xs :: [k]) :: [k] where
  Tail (x ': xs) = xs

と書かなければならなかったところを、

type family Tail (xs :: [k]) :: [k] where
  Tail (_ ': xs) = xs

と書けるようになる。ささいなことだが、型レベルプログラミングジャンキーにとってはナイスな改良だ。

単射なる型族

type family F x y = a | a -> x, a -> yのようにして、型族が単射であることをあらかじめ定義できる。これにより、うまく型推論してくれる場面が増える。型レベルプログラミングフィーンドもこれでさらに活躍できる。

コールスタック

ImplicitParams拡張を有効にしたうえで、?callStack :: CallStackという暗黙のパラメータが使えるようになる。しかしこれはいかがなものか……筆者としてはImplicitParameter自体かなり悪いアイデアだと思う。

コンパイル時間

型周りの大きな拡張により、コンパイル時間も追加されたようだ。エスプレッソを抽出したりラテアートを作る余裕もできるだろう。