License | MIT |
---|---|
Maintainer | mmzk1526@outlook.com |
Portability | GHC |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Similar to Data.TypeID, but the type is statically determined in the type level.
When using TypeID
, if we want to check if the type matches, we usually need
to get the prefix of the TypeID
and compare it with the desired prefix at
runtime. However, with Haskell's type system, we can do this at compile time
instead. We call this TypeID with compile-time prefix a KindID
.
Of course, that would require the desired prefix to be known at compile time. This is actually quite common, especially when we are using one prefix for one table in the database.
For example, suppose we have a function that takes a KindID
with the prefix
"user", it may have a signature like this:
f :: KindID "user" -> IO ()
Then if we try to pass in a KindID
with the prefix "post", the compiler
will complain, thus removing the runtime check and the associated overhead.
All the prefixes are type-checked at compile time, so if we try to pass in invalid prefixes, the compiler (again) will complain.
This module contains functions to generate and parse these type-level TypeIDs as well as conversion functions to and from the usual term-level TypeIDs. These functions are usually used with a type application, e.g.
do tid <- genKindID @"user" ...
Synopsis
- data KindID prefix
- getPrefix :: IDType a => a -> Text
- getUUID :: IDType a => a -> UUID
- getTime :: IDType a => a -> Word64
- type ValidPrefix prefix = (KnownSymbol prefix, LengthSymbol prefix < 64, IsLowerSymbol prefix ~ 'True)
- class ToPrefix a where
- type PrefixSymbol a :: Symbol
- nil :: KindID ""
- nilKindID :: KindID ""
- genKindID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => IO (KindID prefix)
- genKindIDs :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Word16 -> IO [KindID prefix]
- decorate :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => UUID -> KindID prefix
- decorateKindID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => UUID -> KindID prefix
- id2String :: IDConv a => a -> String
- id2Text :: IDConv a => a -> Text
- id2ByteString :: IDConv a => a -> ByteString
- string2ID :: IDConv a => String -> Either TypeIDError a
- text2ID :: IDConv a => Text -> Either TypeIDError a
- byteString2ID :: IDConv a => ByteString -> Either TypeIDError a
- toString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> String
- toText :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> Text
- toByteString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> ByteString
- parseString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => String -> Either TypeIDError (KindID prefix)
- parseText :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Text -> Either TypeIDError (KindID prefix)
- parseByteString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => ByteString -> Either TypeIDError (KindID prefix)
- toTypeID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> TypeID
- fromTypeID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => TypeID -> Maybe (KindID prefix)
Data types
A TypeID with the prefix encoded at type level.
It is dubbed KindID
because we the prefix here is a data kind rather than
a type.
Note that the Show
instance is for debugging purposes only. To pretty-print
a KindID
, use toString
, toText
or toByteString
. However, this
behaviour will be changed in the next major version as it is not useful. By
then, the Show
instance will be the same as toString
.
Instances
type ValidPrefix prefix = (KnownSymbol prefix, LengthSymbol prefix < 64, IsLowerSymbol prefix ~ 'True) Source #
A constraint for valid prefix Symbol
s.
A class that translates any kind to a Symbol
. It is used to translate
custom data kinds to a Symbol
so that they can be used as KindID
prefixes.
For example, suppose we have the following data structure that represents the prefixes we are going to use:
data Prefix = User | Post | Comment
Then we can make it an instance of ToPrefix
like this:
instance ToPrefix 'User where type PrefixSymbol 'User = "user" instance ToPrefix 'Post where type PrefixSymbol 'Post = "post" instance ToPrefix 'Comment where type PrefixSymbol 'Comment = "comment"
Now we can use Prefix as a prefix for KindID
s, e.g.
do userID <- genKindID @'User -- Same as genKindID @"user" postID <- genKindID @'Post -- Same as genKindID @"post" commentID <- genKindID @'Comment -- Same as genKindID @"comment"
type PrefixSymbol a :: Symbol Source #
Instances
ToPrefix (a :: Symbol) Source # | The |
Defined in Data.KindID.Internal type PrefixSymbol a :: Symbol Source # |
KindID generation
genKindID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => IO (KindID prefix) Source #
Generate a new KindID
from a prefix.
It throws a TypeIDError
if the prefix does not match the specification,
namely if it's longer than 63 characters or if it contains characters other
than lowercase latin letters.
genKindIDs :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Word16 -> IO [KindID prefix] Source #
decorate :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => UUID -> KindID prefix Source #
Deprecated: Use decorateKindID
instead.
decorateKindID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => UUID -> KindID prefix Source #
Encoding & decoding (class methods)
id2ByteString :: IDConv a => a -> ByteString Source #
Pretty-print the identifier to a lazy ByteString
.
string2ID :: IDConv a => String -> Either TypeIDError a Source #
Parse the identifier from its String
representation.
text2ID :: IDConv a => Text -> Either TypeIDError a Source #
Parse the identifier from its string representation as a strict Text
.
byteString2ID :: IDConv a => ByteString -> Either TypeIDError a Source #
Parse the identifier from its string representation as a lazy
ByteString
.
Encoding & decoding (KindID
-specific)
toString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> String Source #
toText :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> Text Source #
toByteString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> ByteString Source #
Pretty-print a KindID
to lazy ByteString
. It is id2ByteString
with
concrete type.
parseString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => String -> Either TypeIDError (KindID prefix) Source #
Parse a KindID
from its String
representation. It is parseString
with concrete type.
parseText :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Text -> Either TypeIDError (KindID prefix) Source #
parseByteString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => ByteString -> Either TypeIDError (KindID prefix) Source #
Parse a KindID
from its string representation as a lazy ByteString
. It
is parseByteString
with concrete type.
Type-level & term-level conversion
toTypeID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> TypeID Source #
fromTypeID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => TypeID -> Maybe (KindID prefix) Source #