重複したフィールドラベル
Haskell 2010 では、同じファイルに重複したフィールドラベルを定義できない。たとえば、以下はエラーになる。
data Foo = Foo { same :: Int } data Bar = Bar { same :: Float } -- これはダメ
この問題を解決する案は、OverloadedRecordFields と呼ばれ、苦難の歴史を持つ。実装があるにもかかわらず、
- 実装が一枚岩
- コードの複雑になる割に利益が少ない
などの理由により、GHC へはマージされずにいた。現在では、OverloadedRecordFieldsは、三つの拡張へと分割された:
- DuplicateRecordFields
- OverloadedLabels
- Magic type classes
この中、1. と 2. が GHC 8.0 に入る。
DuplicateRecordFields
DuplicateRecordFields は単純で、同一ファイルで重複したフィールドラベルが「定義」されることを許す。以下は、GHC 8.0 ではエラーにならない。
{-# LANGUAGE DuplicateRecordFields #-} data Foo = Foo { same :: Int } data Bar = Bar { same :: Float }
しかし、フィールドラベルを使おうとするとエラーになる。
{-# LANGUAGE DuplicateRecordFields #-} data Foo = Foo { same :: Int } data Bar = Bar { same :: Float } main :: IO () main = do let x = Foo 1 print $ same x -- これはダメ
型推論はどこで完了するか分からないので、型を取ってこれないらしい。型を明記すれば使える。
{-# LANGUAGE DuplicateRecordFields #-} data Foo = Foo { same :: Int } data Bar = Bar { same :: Float } main :: IO () main = do let x = Foo 1 print $ same (x :: Foo)
これはやってられない感じがする。
OverloadedLabels
この問題を解決するための第一歩が OverloadedLabels である。とっても面倒だが、以下のような記述で、# が付いたフィールドラベルが使えるようになる。
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE DataKinds, TypeFamilies #-} {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} import GHC.OverloadedLabels data Foo = Foo { same :: Int } data Bar = Bar { same :: Float } instance (a ~ Int) => IsLabel "same" (Foo -> a) where fromLabel _ (Foo n) = n instance (a ~ Float) => IsLabel "same" (Bar -> a) where fromLabel _ (Bar d) = d main :: IO () main = do let x = Foo 1 print $ #same x
将来の GHC では、このボイラープレートが自動導出されるようになるそうだ。