Ответ 1
Это не то, для чего Bounded
. Bounded a
просто определяет функции minBound :: a
и maxBound :: a
. Это не вызывает никакой специальной проверки или чего-либо еще.
Вы можете определить ограниченный тип с помощью так называемого интеллектуального конструктора. То есть:
module Probability (Probability) where
newtype Probability = P { getP :: Float }
deriving (Eq,Ord,Show)
mkP :: Float -> Probability
mkP x | 0 <= x && x <= 1 = P x
| otherwise = error $ show x ++ " is not in [0,1]"
-- after this point, the Probability data constructor is not to be used
instance Num Probability where
P x + P y = mkP (x + y)
P x * P y = mkP (x * y)
fromIntegral = mkP . fromIntegral
...
Таким образом, единственный способ сделать Probability
- использовать функцию mkP
в конце концов (это делается для вас, когда вы используете числовые операции с учетом нашего экземпляра Num
), который проверяет, что аргумент находится в диапазоне. Из-за списка экспорта модулей за пределами этого модуля невозможно построить недопустимую вероятность.
Наверное, не тот двухлиний, который вы искали, но хорошо.
Для дополнительной компоновки вы можете отбросить эту функциональность, создав модуль BoundCheck
вместо `Вероятность. Как и выше, кроме:
newtype BoundCheck a = BC { getBC :: a }
deriving (Bounded,Eq,Ord,Show)
mkBC :: (Bounded a) => a -> BoundCheck a
mkBC x | minBound <= x && x <= maxBound = BC x
| otherwise = error "..."
instance (Bounded a) => Num (BoundCheck a) where
BC x + BC y = mkBC (x + y)
...
Таким образом, вы можете получить нужные вам функциональные возможности, когда вы задали вопрос.
Чтобы сделать это, вам понадобится расширение языка {-# LANGUAGE GeneralizedNewtypeDeriving #-}
.