As it appears, both answers of @chi and @Sibi are what Refinement Types are about. I.e., the types which enclose other types, while restricting the range of supported values with a validator. The validation can be done both at run-time and compile-time depending on the use-case.
It just so happens that I've authored "refined", a library, which provides abstractions for both cases. Follow the link for an extensive introduction.
To apply this library in your scenario, in one module define the predicate:
import Refined
import Data.ByteString (ByteString)
data IsEmail
instance Predicate IsEmail ByteString where
validate _ value =
if isEmail value
then Nothing
else Just "ByteString form an invalid Email"
where
isEmail =
error "TODO: Define me"
-- | An alias for convenince, so that there's less to type.
type EmailBytes =
Refined IsEmail ByteString
Then use it in any other module (this is required due to Template Haskell).
You can construct the values both at compile-time and run-time:
-- * Constructing
-------------------------
{-|
Validates your input at run-time.
Abstracts over the Smart Constructor pattern.
-}
dynamicallyCheckedEmailLiteral :: Either String EmailBytes
dynamicallyCheckedEmailLiteral =
refine "email@example.info"
{-|
Validates your input at compile-time with zero overhead.
Abstracts over the solution involving Lift and QuasiQuotes.
-}
staticallyCheckedEmailLiteral :: EmailBytes
staticallyCheckedEmailLiteral =
$$(refineTH "email@example.info")
-- * Using
-------------------------
aFunctionWhichImpliesThatTheInputRepresentsAValidEmail :: EmailBytes -> IO ()
aFunctionWhichImpliesThatTheInputRepresentsAValidEmail emailBytes =
error "TODO: Define me"
where
{-
Shows how you can extract the "refined" value at zero cost.
It makes sense to do so in an enclosed setting.
E.g., here you can see `bytes` defined as a local value,
and we can be sure that the value is correct.
-}
bytes :: ByteString
bytes =
unrefine emailBytes
Also please beware that this is just a surface of what Refinement Types can cover. There's actually much more useful properties to them.