Smart constructors
Один простой способ сделать это — использовать интеллектуальную инкапсуляцию и интеллектуальные конструкторы:
module HoursAndMinutes (Hours, mkHours, getHours, Minutes, mkMinutes, getMinutes) where
newtype Hours = UnsafeHours Int
mkHours :: Int -> Maybe Hours
mkHours n | 0 <= n && n < 24 = Just (UnsafeHours n)
| otherwise = Nothing
getHours :: Hours -> Int
getHours (UnsafeHours n) = n
newtype Minutes = UnsafeMinutes Int
mkMinutes :: Int -> Maybe Minutes
mkMinutes n | 0 <= n && n < 60 = Just (UnsafeMinutes n)
| otherwise = Nothing
getMinutes :: Minutes -> Int
getMinutes (UnsafeMinutes n) = n
Теперь в вашем другом коде, если вы импортируете HoursAndMinutes
, вы не можете построить недопустимые Hours
или Minutes
.
data Clock = Clock {hours :: Hours, minutes :: Minutes}
Тогда это приведет к Nothing
:
Clock <$> mkHours 34 <*> mkMinutes 236
Refined
Вы можете использовать встроенные предикаты из пакета refined
, чтобы немного упростить этот подход:
data Clock = Clock
{ hours :: Refined (FromTo 0 23) Int
, minutes :: Refined (FromTo 0 59) Int
}
Затем вы можете построить его с помощью:
Clock <$> refine 34 <*> refine 236
Который будет Left (RefineSomeException ...)
.
Недостатком по-прежнему является то, что проверки выполняются во время выполнения. Вы можете получить проверки времени компиляции с помощью Template Haskell:
Clock $$(refineTH 34) $$(refineTH 236)
Это вызовет исключение во время компиляции.
Liquid Haskell
Вы можете сделать это более удобным, используя Liquid Haskell, как предлагает Виллем ван Онсем в своем комментарии. :
module Clock where
data Clock = Clock { hours :: Int, minutes :: Int } deriving Show
{-@ data Clock = Clock
{ hours :: {h:Int | 0 <= h && h < 24}
, minutes :: {m:Int | 0 <= m && m < 60}
} @-}
goodClock :: Clock
goodClock = Clock 16 49
badClock :: Clock
badClock = Clock 34 236 -- this gives an error
Попробуйте здесь.
person
Noughtmare
schedule
19.07.2021
data Hour = HOne | HTwo | ... | HTwentyThree
иdata Minute = MOne | MTwo | ... | MFiftyNine
, а затем определить часы какClock { hour :: Hour, minutes :: Minute }
. - person Willem Van Onsem   schedule 19.07.2021< 24
и< 60
. - person Noughtmare   schedule 19.07.2021