由于违反了minBound和maxBound,我预计以下代码会因类型错误而失败。但是,正如您所看到的,它会在没有标记错误的情况下通过。
{-# OPTIONS_GHC -XTypeSynonymInstances #-}
module Main where
type Probability = Float
instance Bounded Probability where
minBound = 0.0
maxBound = 1.0
testout :: Float -> Probability
testout xx = xx + 1.0
main = do
putStrLn $ show $ testout 0.5
putStrLn $ show $ testout (-1.5)
putStrLn $ show $ testout 1.5
在Prelude中我得到了这个
*Main> :type (testout 0.5)
(testout 0.5) :: Probability
在提示我得到这个:
[~/test]$runhaskell demo.hs
1.5
-0.5
2.5
显然,我没有正确宣布有限,我确信我在语法上做错了。谷歌关于有界类型类没有太多简单的东西,所以任何帮助都会非常感激。
答案 0 :(得分:22)
这不是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 #-}
。