{-| This module provides support for optionality records. Optionality records are used to specify interfaces with optional input data. Compared to an ordinary record type, an optionality record type states for every field whether it is required or optional. This is done by a slight abuse of field names. A field name @/name/@ is replaced by either @'Req' /name/@ or @'Opt' /name/@. Optionality record types are never used directly in types of actual values. Instead, they are converted into ordinary record types with the type functions 'All' and 'Required'. -} module FRP.Grapefruit.Record.Optionality ( Req, Opt, OptRecord (type All, type Required) ) where -- FRP.Grapefruit import FRP.Grapefruit.Signal as Signal import FRP.Grapefruit.Record as Record -- |A marker for required fields. data Req name -- |A marker for optional fields. data Opt name -- |The class of all optionality record types. class (Record (All optRecord), Record (Required optRecord)) => OptRecord (optRecord :: * -> *) where {-| Converts an optionality record type into an ordinary record type by dropping all 'Req' and 'Opt' annotations. -} type All optRecord :: * -> * {-| Extracts all required fields from an optionality record type and drops their 'Req' annotations. -} type Required optRecord :: * -> * instance OptRecord X where type All X = X type Required X = X instance (OptRecord optRecord) => OptRecord (optRecord :& Req name ::: signal `Of` val) where type All (optRecord :& Req name ::: signal `Of` val) = All optRecord :& name ::: signal `Of` val type Required (optRecord :& Req name ::: signal `Of` val) = Required optRecord :& name ::: signal `Of` val instance (OptRecord optRecord) => OptRecord (optRecord :& Opt name ::: signal `Of` val) where type All (optRecord :& Opt name ::: signal `Of` val) = All optRecord :& name ::: signal `Of` val type Required (optRecord :& Opt name ::: signal `Of` val) = Required optRecord