Safe Haskell | None |
---|---|
Language | Haskell2010 |
Generic conversion of Haskell data types to Elm types.
Synopsis
- class Elm a where
- toElmDefinition :: Proxy a -> ElmDefinition
- elmRef :: forall a. Elm a => TypeRef
- elmNewtype :: forall a. Elm a => Text -> Text -> ElmDefinition
- class GenericElmDefinition (f :: k -> Type) where
- genericToElmDefinition :: f a -> ElmDefinition
- class GenericElmConstructors (f :: k -> Type) where
- genericToElmConstructors :: TypeName -> f a -> NonEmpty GenericConstructor
- class GenericElmFields (f :: k -> Type) where
- genericToElmFields :: TypeName -> f a -> [(TypeRef, Maybe Text)]
- data GenericConstructor = GenericConstructor {
- genericConstructorName :: !Text
- genericConstructorFields :: ![(TypeRef, Maybe Text)]
- toElmConstructor :: GenericConstructor -> Either (NonEmpty ElmRecordField) ElmConstructor
- type family HasNoTypeVars (f :: k) :: Constraint where ...
- type family TypeVarsError (t :: k) (n :: Nat) :: ErrorMessage where ...
- type family HasLessThanEightUnnamedFields (f :: k) :: Constraint where ...
- type family FieldsError (t :: k) :: ErrorMessage where ...
- type family CheckFields (f :: k -> Type) :: Nat where ...
- type family Max (x :: Nat) (y :: Nat) :: Nat where ...
- type family HasNoNamedSum (f :: k) :: Constraint where ...
- type family NamedSumError (t :: k) :: ErrorMessage where ...
- type family CheckNamedSum (f :: k -> Type) :: Bool where ...
- type family CheckConst (f :: k -> Type) :: Bool where ...
- stripTypeNamePrefix :: TypeName -> Text -> Text
Main data type for the user
Typeclass that describes how Haskell data types are converted to Elm ones.
Nothing
toElmDefinition :: Proxy a -> ElmDefinition Source #
toElmDefinition :: (HasNoTypeVars a, HasLessThanEightUnnamedFields a, HasNoNamedSum a, Generic a, GenericElmDefinition (Rep a)) => Proxy a -> ElmDefinition Source #
Instances
elmRef :: forall a. Elm a => TypeRef Source #
Returns TypeRef
for the existing type. This function always returns the
name of the type without any type variables added.
Smart constructors
elmNewtype :: forall a. Elm a => Text -> Text -> ElmDefinition Source #
Generic utilities
class GenericElmDefinition (f :: k -> Type) where Source #
Generic typeclass to generate whole ElmDefinition
. It has only one
instance: for the first top-level metadata that contains metainformation about
data type like data type name
. Then it collects all constructors of the data
type and decides what to generate.
genericToElmDefinition :: f a -> ElmDefinition Source #
Instances
(Datatype d, GenericElmConstructors f) => GenericElmDefinition (D1 d f :: k -> Type) Source # | |
Defined in Elm.Generic genericToElmDefinition :: D1 d f a -> ElmDefinition Source # |
class GenericElmConstructors (f :: k -> Type) where Source #
Typeclass to collect all constructors of the Haskell data type generically.
genericToElmConstructors Source #
:: TypeName | Name of the data type; to be stripped |
-> f a | Generic value |
-> NonEmpty GenericConstructor | List of the data type constructors |
Instances
(GenericElmConstructors f, GenericElmConstructors g) => GenericElmConstructors (f :+: g :: k -> Type) Source # | If it's a sum type then just combine constructors |
Defined in Elm.Generic genericToElmConstructors :: TypeName -> (f :+: g) a -> NonEmpty GenericConstructor Source # | |
(Constructor c, GenericElmFields f) => GenericElmConstructors (C1 c f :: k -> Type) Source # | Create singleton list for case of a one constructor. |
Defined in Elm.Generic genericToElmConstructors :: TypeName -> C1 c f a -> NonEmpty GenericConstructor Source # |
class GenericElmFields (f :: k -> Type) where Source #
Collect all fields when inside constructor.
Instances
GenericElmFields (U1 :: k -> Type) Source # | Constructor without fields. |
Defined in Elm.Generic | |
(GenericElmFields f, GenericElmFields g) => GenericElmFields (f :*: g :: k -> Type) Source # | If multiple fields then just combine all results. |
Defined in Elm.Generic | |
(Selector s, Elm a) => GenericElmFields (S1 s (Rec0 a) :: k -> Type) Source # | Single constructor field. |
Defined in Elm.Generic |
data GenericConstructor Source #
Intermediate data type to help with the conversion from Haskell constructors to Elm AST. In Haskell constructor fields may have names but may not have.
toElmConstructor :: GenericConstructor -> Either (NonEmpty ElmRecordField) ElmConstructor Source #
Generic constructor can be in one of the three states:
- No fields: enum constructor.
- All fields have names: record constructor.
- Not all fields have names: plain constructor.
Type families for compile-time checks
type family HasNoTypeVars (f :: k) :: Constraint where ... Source #
This type family checks whether data type has type variables and throws custom compiler error if it has. Since there's no generic way to get all type variables, current implementation is limited only to 6 variables. This looks like a reasonable number.
HasNoTypeVars (t a b c d e f) = TypeError (TypeVarsError t 6) | |
HasNoTypeVars (t a b c d e) = TypeError (TypeVarsError t 5) | |
HasNoTypeVars (t a b c d) = TypeError (TypeVarsError t 4) | |
HasNoTypeVars (t a b c) = TypeError (TypeVarsError t 3) | |
HasNoTypeVars (t a b) = TypeError (TypeVarsError t 2) | |
HasNoTypeVars (t a) = TypeError (TypeVarsError t 1) | |
HasNoTypeVars t = () |
type family TypeVarsError (t :: k) (n :: Nat) :: ErrorMessage where ... Source #
TypeVarsError t n = ((((Text "'elm-street' currently doesn't support Generic deriving of the 'Elm' typeclass" :$$: ((((Text "for data types with type variables. But '" :<>: ShowType t) :<>: Text "' has ") :<>: ShowType n) :<>: Text " variables.")) :$$: Text "") :$$: Text "See the following issue for more details:") :$$: Text " * https://github.com/Holmusk/elm-street/issues/45") :$$: Text "" |
type family HasLessThanEightUnnamedFields (f :: k) :: Constraint where ... Source #
This type family checks whether each constructor of the sum data type has less than eight unnamed fields and throws custom compiler error if it has.
HasLessThanEightUnnamedFields t = If (CheckFields (Rep t) <=? 8) (() :: Constraint) (TypeError (FieldsError t)) |
type family FieldsError (t :: k) :: ErrorMessage where ... Source #
type family CheckFields (f :: k -> Type) :: Nat where ... Source #
CheckFields (D1 _ f) = CheckFields f | |
CheckFields (f :+: g) = Max (CheckFields f) (CheckFields g) | |
CheckFields (C1 _ f) = CheckFields f | |
CheckFields (f :*: g) = CheckFields f + CheckFields g | |
CheckFields (S1 (MetaSel (Just _) _ _ _) _) = 0 | |
CheckFields (S1 _ _) = 1 | |
CheckFields _ = 0 |
type family HasNoNamedSum (f :: k) :: Constraint where ... Source #
This type family checks whether each constructor of the sum data type has less than eight unnamed fields and throws custom compiler error if it has.
HasNoNamedSum t = If (CheckNamedSum (Rep t)) (TypeError (NamedSumError t)) (() :: Constraint) |
type family NamedSumError (t :: k) :: ErrorMessage where ... Source #
type family CheckNamedSum (f :: k -> Type) :: Bool where ... Source #
Is the data type id Sum type with named fields?
CheckNamedSum (D1 _ f) = CheckNamedSum f | |
CheckNamedSum (f :+: g) = CheckConst f || CheckConst g | |
CheckNamedSum _ = False |
type family CheckConst (f :: k -> Type) :: Bool where ... Source #
Check if Sum type has named fields at least for one of the Constructors.
CheckConst (f :+: g) = CheckConst f || CheckConst g | |
CheckConst (C1 _ f) = CheckConst f | |
CheckConst (S1 (MetaSel (Just _) _ _ _) _) = True | |
CheckConst (f :*: g) = CheckConst f || CheckConst g | |
CheckConst _ = False |
Internals
stripTypeNamePrefix :: TypeName -> Text -> Text Source #
Strips name of the type name from field name prefix.
>>>
stripTypeNamePrefix (TypeName "User") "userName"
"name"
>>>
stripTypeNamePrefix (TypeName "HealthReading") "healthReadingId"
"id"
>>>
stripTypeNamePrefix (TypeName "RecordUpdate") "ruRows"
"rows"
>>>
stripTypeNamePrefix (TypeName "Foo") "foo"
"foo"
>>>
stripTypeNamePrefix (TypeName "Foo") "abc"
"abc"