【问题标题】:How do you use the Bounded typeclass in Haskell to define a type with a floating point range?如何使用 Haskell 中的 Bounded 类型类来定义具有浮点范围的类型?
【发布时间】:2023-03-12 04:57:01
【问题描述】:

我预计以下代码会因违反 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

在前奏曲中我明白了

*Main> :type (testout 0.5)
(testout 0.5) :: Probability

在提示符下我得到这个:

[~/test]$runhaskell demo.hs
1.5
-0.5
2.5

很明显,我没有正确声明 Bounded,而且我确定我在语法上做错了什么。 Google 上没有太多关于有界类型类的简单资料,因此我们将不胜感激。

【问题讨论】:

    标签: haskell types typeclass


    【解决方案1】:

    这不是Bounded 的用途。 Bounded a 只定义了函数minBound :: amaxBound :: 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 模块而不是Probability 来分解此功能。和上面一样,除了:

    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 #-}

    【讨论】:

    • 非常有帮助,非常感谢。一个问题:您使用省略号(“...”)来定义 mkP 和 mkBC 在 Num 类型的事物上与现有运算符交互的各种方式。我想这样做的目的是为概率类型的事物定义算术运算符,这些运算符通过 mkP 继续运行输出以进行边界检查。
    • 如果您不知道在哪里寻找Num 方法:hackage.haskell.org/packages/archive/base/4.2.0.2/doc/html/…
    • 概率实际上是一个数字吗?基础表示是真的,您必须对该基础表示进行算术运算来评估概率表达式的结果。但是对概率的实际操作将是(con/dis)junction 和 inversion。
    猜你喜欢
    • 2011-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 2013-11-05
    相关资源
    最近更新 更多