generated at
OverloadedLabels
fieldに # を付けた、 #foo のような関数を、多相getterとして扱える
OverloadedRecordFieldsの3分割されたものの1つ



GHC 9時代に、ボトムアップに理解しようとするとこうなる
だから出た当時の資料とは説明の仕方がやや異なるmrsekut
まず、この拡張を有効にしなくとも以下のようなことができる
hs
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DataKinds #-} data Hoge = Hoge { id :: Int } data Piyo = Piyo { id :: Int } g :: Int g = getField @"id" (Hoge 1) f :: Int f = getField @"id" (Piyo 1)
2つのRecordがあり、field名が重複しているが、 getField @"id" という関数が多相であるので問題なくgetterとして利用できる
これは(Magic Type Classesと)HasField型クラスの能力である
ただ、この getField @"hoge" というgetter部分が冗長
これを #hoge と書けるようにしたい
前準備として以下のようなinstanceを定義しておく
hs
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} import GHC.OverloadedLabels (IsLabel (fromLabel)) import GHC.Records (HasField (getField)) instance HasField x r a => IsLabel x (r -> a) where fromLabel = getField @x
IsLabel型クラスのinstanceを定義する
このinstance定義をするために↑のような3つの拡張が必要になる
ここにも OverloadedLabels は含まれていないmrsekut
なんでこの前準備を自分で書かないといけないの #??
OverloadedLabels を有効にしたら暗黙的にやってくれるのでも良い気もするけど
自分で定義するRecord型に依存していないので内部で定義できるはずmrsekut
準備は整ったので、 OverloadedLabels を使うと #hoge でアクセスできるようになる
hs
{-# LANGUAGE OverloadedLabels #-} data Hoge = Hoge { hoge :: Int } g :: Int g = #hoge (Hoge 1)


OverloadedLabels が出た当時は、Magic Type Classesがなかったので、
自前で IsLabel のisntanceを定義する必要があった
上の例に合わせるなら
hs
instance IsLabel "hoge" (Hoge -> Int) where fromLabel Hoge { hoge } = hoge
こういうのを自分で定義したRecordの数だけ定義する必要があったmrsekut
GHC 8.2以降はMagic Type Classesがあるのでわざわざ書かなくて良い



というかGHC9.2.1で入った他の拡張を使うのであれば OverloadedLabels の出番はなくなるのではないか?
どういう仕組で動いているのかあまり理解していない
IsLabel型クラスの定義の中身がよくわからない
IsLabel instanceは x という多相な型に対して定義しているがこれはなんの機能なのか
#hoge という関数の型は、 $dIsLabel :: IsLabel "hoge" (Hoge -> Int) と表示されるが、どういう意味なのか
#hoge はなにかの関数のaliasだったりするのか











>code

OverloadedLabels#61704a0d19827000003ce870の話を全部一気に書くと
hs
{-# LANGUAGE TypeApplications, DataKinds #-} {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables #-} {-# LANGUAGE OverloadedLabels #-} import GHC.OverloadedLabels (IsLabel (fromLabel)) import GHC.Records (HasField (getField)) instance HasField x r a => IsLabel x (r -> a) where fromLabel = getField @x data Hoge = Hoge { hoge :: Int } g :: Int g = #hoge (Hoge 1)