{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -- | Derive record field lenses generically. -- -- == Usage with labels in "Optics.Label" -- -- "Optics.Label" provides 'Optics.Label.LabelOptic' class which powers -- the @OverloadedLabels@ instance for optics type. -- -- It's possible to use 'L.HasField' and 'field' to derive instances -- generically. If we have a simple record type which has 'GHC.Generics.Generic' -- instance: -- -- @ -- data Ex = Ex { exA :: Int, exB :: Char } deriving (Generic) -- @ -- -- We can derive 'Optics.Label.LabelOptic' instances for all its fields -- at once: -- -- @ -- instance ('HasField' name Ex a, a ~ b) => LabelOptic name A_Lens Ex Ex a b where -- labelOptic = 'field' @name -- @ -- -- /Note:/ GHC will ask you to enable a lot of extensions, do it. -- Youn need to enable @UndecidableInstances@ in particular to make -- @FunctionalDependencies@ check pass. -- module Data.Generics.Optics.Lite ( field, L.HasField, ) where import Data.Kind (Type) import GHC.TypeLits (Symbol) import Optics.Core (Lens', lensVL) import qualified Data.Generics.Lens.Lite as L ------------------------------------------------------------------------------- -- Public API ------------------------------------------------------------------------------- -- | A lens that focuses on a field with a given name. -- Compatible with the optics package's 'Optics.Lens.Lens' type. -- -- __Note:__ the lens is /simple/, i.e. doesn't allow type-changing updates. -- This keeps the implementation small and quick. -- -- You also may want to specify -- @ -- {-\# OPTIONS_GHC -funfolding-keeness-factor=100 #-} (or some other arbitrarily large number) -- @ -- for GHC to inline more aggressively. -- field :: forall (name :: Symbol) (r :: Type) (a :: Type). L.HasField name r a => Lens' r a field = lensVL (L.field @name)