{-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -- Necessary for correct type for @setField@ {-# LANGUAGE AllowAmbiguousTypes #-} -- | Provide @Prelude@-like environment when using @RebindableSyntax@ -- -- If you want to use @large-records@ with 'OverloadedRecordDot' and -- 'OverloadedRecordUpdate', you need to enable the @RebindableSyntax@ language -- extension. You can then import this module to get a standard environment -- back, with one exception; see 'getField' for details. module Data.Record.Overloading ( module Prelude , Control.Arrow.app , Control.Arrow.arr , Control.Arrow.first , Control.Arrow.loop , (Control.Arrow.>>>) , (Control.Arrow.|||) , Data.String.fromString , GHC.OverloadedLabels.fromLabel -- * New definitions , ifThenElse , getField , setField ) where import qualified Control.Arrow import qualified Data.String import qualified GHC.OverloadedLabels import qualified GHC.Records.Compat {------------------------------------------------------------------------------- Other exports -------------------------------------------------------------------------------} ifThenElse :: Bool -> a -> a -> a ifThenElse :: forall a. Bool -> a -> a -> a ifThenElse Bool b a x a y = if Bool b then a x else a y -- | Get record field -- -- This is /NOT/ the standard @getField@ from "GHC.Records", but is instead -- defined in terms of "GHC.Records.Compat.HasField". As a consequence we do not -- currently support @OverloadedRecordDot@ without @RebindableSyntax@. -- (For ghc 9.2 and 9.4 @RebindableSyntax@ is required /anyway/ when using -- @OverloadedRecordUpdate@, so this is less of a limitation than it might -- seem.) -- -- Unfortunately, we /cannot/ currently support 'GHC.Records.HasField'; in the -- remainder of this comment we explain why. Consider a record such as -- -- > {-# ANN type Person largeRecord #-} -- > data Person = Person { name :: String } -- -- The internal representation of this record generated by @large-records@ -- looks something like this: -- -- > data Person = forall a. a ~ String => Person { name :: a } -- -- This representation prevents ghc from generating record accessors, whilst -- at the same time still making it possible to define and pattern match on -- records in the normal way. Unfortunately, although GHC does not generate -- a 'HasField' instance for such a record, it /also/ prevents us from -- defining our own: -- -- If a field has a higher-rank or existential type, the corresponding -- HasField constraint will not be solved automatically (as described above), -- but in the interests of simplicity we do not permit users to define their -- own instances either. -- -- <https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/hasfield.html#solving-hasfield-constraints> -- -- There is a proposal to change this -- (<https://github.com/ghc-proposals/ghc-proposals/pull/515>), -- but for now we instead rely on 'GHC.Records.Compat.HasField', for which no -- such restrictions exist. getField :: forall x r a. GHC.Records.Compat.HasField x r a => r -> a getField :: forall {k} (x :: k) r a. HasField x r a => r -> a getField = forall a b. (a, b) -> b snd forall b c a. (b -> c) -> (a -> b) -> a -> c . forall {k} (x :: k) r a. HasField x r a => r -> (a -> r, a) GHC.Records.Compat.hasField @x setField :: forall x r a. GHC.Records.Compat.HasField x r a => r -> a -> r setField :: forall {k} (x :: k) r a. HasField x r a => r -> a -> r setField = forall a b. (a, b) -> a fst forall b c a. (b -> c) -> (a -> b) -> a -> c . forall {k} (x :: k) r a. HasField x r a => r -> (a -> r, a) GHC.Records.Compat.hasField @x