{-# 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