NoFieldSelectorsを有効にするとmakeFieldsが使えなくなる問題のワークアラウンド
前提
NoFieldSelectors を使うと、一々フィールドにコンストラクタのプレフィクスを付けなくても良くなります。
しかしlens
のmakeFields
などは、コンストラクタのプレフィクスか_
でフィールドが始まることを期待しているため、プレフィクスを無くしたらアクセサを作ってくれなくなります。
そもそもNoFieldSelectors
があればlens要らないのではとか思わなくはないですが、まだRecord Dot Syntaxでは、ネストしたデータを更新する実装が自動で生えてくるわけではなさそうなこと。複数の型を跨いだ更新などに便利なこと。
lensには単純に代入する以外のアクセサがあることを考えると、まだまだlensは使っていきたいですね。
よって解決する極めて簡単な関数を書きました。
解決
module Control.Lens.TH.NoFieldSelectors (makeLensesId) where
import Control.Lens
import qualified Data.Char as C
import Language.Haskell.TH
-- | `NoFieldSelectors`を有効にした環境では、
-- フィールドにプレフィクスを付けなくて済みますが、
-- lensがアクセサを作る条件を満たさなくなるため雑に許可します。
makeLensesId :: Name -> DecsQ
makeLensesId = makeLensesWith idRules
idRules :: LensRules
idRules = defaultFieldRules & lensField .~ idNamer
idNamer :: FieldNamer
idNamer _ _ field =
let fieldPart = nameBase field
classNamePart = case fieldPart of
x : xs -> C.toUpper x : xs
[] -> error "field is empty"
in [MethodName (mkName $ "Has" ++ classNamePart) (mkName fieldPart)]
このmakeLensesId
をmakeLenses
の変わりに使えば完了です。しかしGHC 9.2の動きも考えると、
lensのデフォルト動作でアクセサを作っても良い気がしますね。そのへんも含めてlensにissueを建てることにします。