Как представляется, оба ответа от @chi и @Sibi - это то, что касается типов уточнения. I.e., типы, которые включают другие типы, ограничивая диапазон поддерживаемых значений валидатором. Проверка может выполняться как во время выполнения, так и во время компиляции в зависимости от варианта использования.
Так получилось, что я создал "refined", библиотеку, которая обеспечивает абстракции для обоих случаев. Перейдите по ссылке для широкого ознакомления.
Чтобы применить эту библиотеку в вашем сценарии, в одном модуле определить предикат:
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
затем использовать его в любом другом модуле (это требуется в связи с Template Haskell).
Вы можете построить значения как во время компиляции и время выполнения:
-- * Constructing
-------------------------
{-|
Validates your input at run-time.
Abstracts over the Smart Constructor pattern.
-}
dynamicallyCheckedEmailLiteral :: Either String EmailBytes
dynamicallyCheckedEmailLiteral =
refine "[email protected]"
{-|
Validates your input at compile-time with zero overhead.
Abstracts over the solution involving Lift and QuasiQuotes.
-}
staticallyCheckedEmailLiteral :: EmailBytes
staticallyCheckedEmailLiteral =
$$(refineTH "[email protected]")
-- * 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
Также, пожалуйста, учтите, что это только поверхность, что типы Доработка может покрыть. На самом деле у них гораздо больше полезных свойств.
Сделать неизменный тип, конструктор бросает, если данные некорректны. – ildjarn
В Haskell вы можете записать тип регулярных выражений RegExp: включить «DataKinds», и теперь вы можете записать тип данных, действительный для данного regexp 'RegData :: RegExp -> *', и * singleton * типы для регулярных выражений 'REGEXP :: RegExp -> *'. Вероятно, вам также понадобится проверительный синтаксический анализатор 'regParse :: REGEXP r -> String -> Maybe (RegData r)', поэтому вы можете перейти от строк к проверенным данным, учитывая значение singleton для регулярного выражения, которое вы хотите. Если вы можете написать распознаватель регулярных выражений, то 'regParse' является доказательством, уточняющим ту же идею. – pigworker
"действительный адрес электронной почты (отмеченный против некоторого Regex)" Не очень хороший пример, потому что очень сложно создать регулярное выражение, которое может правильно соответствовать полному набору действительных адресов электронной почты. – JAB