Вопрос по validation, haskell, constructor – Проверка ввода в конструкторах данных Haskell

13

Как добавить проверки ввода в конструкторы данных Haskell? Скажем, у меня есть

import Data.Time.Calendar

data SchedulePeriod = SchedulePeriod { startDate :: Day
    , endDate :: Day
    , accrualStart :: Day
    , accrualEnd :: Day
    , resetDate :: Day
    , paymentDate :: Day
    , fraction :: Double }
    deriving (Show)

и я хочу наложить ограничениеstartDate < endDate, Есть ли способ сделать это без создания абстрактного типа данных?

возможный дубликатHow to make a type with restrictions ehird

Ваш Ответ

2   ответа
13

чтобы я мог объяснить умные деструкторы, которые я упомянул в комментарии, и я не могу вписать объяснение в комментарии.

Допустим, у вас есть тип:

data T x y z = A | B x | C y z

ehird уже объяснил, как абстрагироваться от конструктора, который просто предназначен для «умного» Конструкторы. Как вы упомянули, это требует сокрытия конструкторов, и тогда вы не сможете использовать их для сопоставления с образцом. Тем не менее, вы можете решить эту проблему, используя «умный» деструктор, который эквивалентен сопоставлению с шаблоном для каждого возможного конструктора.

Чтобы объяснить это, давайте сначала начнем с того, как мы напишем функцию типа T, если конструкторы были представлены:

myFunction :: T x y z -> d
myFunction t = case t of
    A     -> f1
    B x   -> f2 x
    C y z -> f3 y z

Из сигнатуры типа функции мы знаем, что типыf1, f2, а такжеf3 должно быть:

f1 :: d
f2 :: x -> d
f3 :: y -> z -> d

Так что, если мы будем обобщатьmyFunction чтобы быть умным деструктором, мы просто передаемf1, f2, а такжеf3 в качестве параметров к нему:

smartDestructor :: d -> (x -> d) -> (y -> z -> d) -> t -> d
smartDestructor f1 f2 f3 t = case t of
    A     -> f1
    B x   -> f2 x
    C y z -> f3 y z

Так что если вы экспортируетеsmartDestructorтогда люди могут в основном сопоставлять шаблоны с вашим типом, не нуждаясь в доступе к конструкторам.

Если вы когда-либо использовалиmaybe или жеeither раньше вы использовали умный деструктор, хотя в этих случаях конструкторы не скрыты, поэтому они в основном предоставляются в качестве вспомогательных функций:

maybe :: b -> (a -> b) -> Maybe a -> b
maybe f1 f2 m = case m of
    Nothing -> f1
    Just  a -> f2 x

either :: (a -> c) -> (b -> c) -> Either a b -> c
either f1 f2 e = case e of
    Left  a -> f1 a
    Right b -> f2 b

В вашем случае, цель умного деструктора состоит в том, чтобы вы могли скрывать конструкторы, а не открывать их.

Error: User Rate Limit Exceededweb.archiveorange.com/archive/v/nDNOvgzSRV6TNq8KhCgZ
Error: User Rate Limit ExceededandError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded quant_dev
Error: User Rate Limit Exceededucsd-progsys.github.io/liquidhaskell-tutorial/01-intro.html
Error: User Rate Limit Exceeded quant_dev
17

умный конструктор проверяет предварительное условие перед созданием значения и не экспортирует используемый им реальный конструктор. Конечно, это создание абстрактного типа данных, как вы сказали.

Единственный способ достичь этого без умного конструктора будетreally злой хакер системы типов (и вы не сможете использовать стандартDay тип).

Error: User Rate Limit Exceeded quant_dev
Error: User Rate Limit Exceeded quant_dev
Error: User Rate Limit ExceededmaybeError: User Rate Limit Exceededeither).
Error: User Rate Limit Exceeded

Похожие вопросы