helloPerson { name } = "Hello, " ++ name ++ "."hello me
OverloadedLabels
#name という記法が使えるようになる
#name me -- > "Kazuki"
そのためには準備が必要
:set -XDataKinds -XFlexibleInstances -XMultiParamTypeClassesimport GHC.OverloadedLabels (IsLabel (fromLabel))
instanceIsLabel "name" (Person -> String) where
fromLabel Person { name } = name
使用側
:set -XFlexibleContexts#name me :: String
しかし、全部に IsLabel のインスタンスを定義するのはしんどい
Magic type classes
HasField クラスのインスタンスが自動的に生成されるようになった
import GHC.Records (HasField (getField))
instanceHasField "name" PersonStringwhere
getField Person { name } = name
HasField なら IsLabel であるとすればよい
instanceHasField x r a => IsLabel x (r -> a) where
fromLabel = getField @x
:set -XDuplicateRecordFields -XOverloadedLabels
:set -XFlexibleContexts -XFlexibleInstances -XMultiParamTypeClassesimport GHC.OverloadedLabels (IsLabel (fromLabel))
import GHC.Records (HasField (getField))
instanceHasField x r a => IsLabel x (r -> a) where
fromLabel = getField @x
dataPerson = Person { name :: String }dataCompany = Company { name :: String }let me = Person"Kazuki"let iij = Company"IIJ"#name me :: String#name iij :: String
調べきれていないところ
instance HasField x r a => IsLabel x (r -> a) はライブラリー内で書いてしまってよい?
他のライブラリーが同様のインスタンスを定義していたら衝突するのでは?
instance HasField x r a => IsLabel x (r -> a) は将来的には標準で定義される?
Record Set Field Proposal
今のところ get しかできないので set もできるようにしよう
classHasField x r a | x r -> a where
hasField :: r -> (a -> r, a)
-- OR
getField :: r -> a
setField :: r -> a -> r