{-# LANGUAGE CPP, FlexibleInstances, InstanceSigs,
             MultiParamTypeClasses, ScopedTypeVariables,
             TypeApplications, TypeFamilies, TypeOperators,
             UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Concise vinyl record field lens syntax. This module exports an
-- orphan instance to make working with labels a bit more powerful. It
-- will conflict with other libraries that provide special syntax for
-- labels (i.e. placing a label in function application position, as
-- in @#age 23@, or using a label as a lens).
--
-- Example:
-- @fieldRec (#x =: True, #y =: 'b') :: FieldRec '[ '("x", Bool), '("y", Char) ]@
-- @fieldRec (#x =: True, #y =: 'b') & #x %~ not@
module Data.Vinyl.Syntax where
import Data.Vinyl.Derived (HasField, (:::), rfield)
import Data.Vinyl.Functor (ElField)
import Data.Vinyl.Lens (RecElemFCtx, rlens')
import GHC.OverloadedLabels (IsLabel(..))
-- import GHC.TypeLits (KnownSymbol)

-- | Concise record construction syntax. Example: @record (#name "Joe", #age 23)@.
-- instance forall s a b. (KnownSymbol s, b ~ ElField '(s,a))
--   => IsLabel s (a -> b) where
-- #if __GLASGOW_HASKELL__ < 802
--   fromLabel _ = Field @s @a
-- #else
--   fromLabel = Field @s @a
-- #endif

-- | Concise 'ElField' lenses. Example @myRec & #name %~ map
-- toUpper@.
--
-- Credit to Tikhon Jelvis who shared this technique on the
-- Haskell-Cafe mailing list on December 23, 2017.
instance forall s t t' ts ts' f record a' b'.
  (HasField record s ts ts' t t', Functor f, RecElemFCtx record ElField,
   a' ~ (t -> f t'), b' ~ (record ElField ts -> f (record ElField ts')))
  => IsLabel s (a' -> b') where
#if __GLASGOW_HASKELL__ < 802
  fromLabel _ = rlens' @(s ::: t) . rfield
#else
  fromLabel :: (t -> f t') -> (record ElField ts -> f (record ElField ts'))
  fromLabel = rlens' @(s ::: t) . rfield
#endif