(为这个怪异的标题表示歉意,但我想不出更好的标题了。)

对于个人Haskell项目,我想拥有“绝对值”(如频率)和相对值(如两个频率之间的比率)的概念。在我的上下文中,添加两个绝对值是没有意义的:一个可以添加相对值以产生新的相对值,并且可以将绝对值添加一个相对值以产生新的绝对值(同样用于减法)。

我已经为这些定义了类型类:请参见下文。但是,请注意,运算符##+#+具有类似的结构(##-#-同样)。因此,我希望合并这些运算符,以便有一个加法运算符,该运算符将一个相对值相加(同样,一个减法运算符也将导致一个相对值)。 更新:为了明确起见,我的目标是将##+#+统一为一个运算符。我的目标不是将其与现有(Num)+运算符统一。

但是,我看不到如何使用类型类来做到这一点。

问题:可以这样做吗?如果可以,怎么做?还是我不应该尝试?

以下是我目前拥有的:

{-# LANGUAGE MultiParamTypeClasses #-}

class Abs a where
  nullPoint :: a

class Rel r where
  zero :: r
  (##+) :: r -> r -> r
  neg :: r -> r

  (##-) :: Rel r => r -> r -> r
  r ##- s = r ##+ neg s

class (Abs a, Rel r) => AbsRel a r where
  (#+) :: a -> r -> a
  (#-) :: a -> a -> r

最佳答案

我认为您正在寻找一种称为Torsor的概念。扭转器由一组值,一组差和一个将差添加到值的算子组成。另外,差异集必须形成一个加性基团,因此差异也可以加在一起。

有趣的是,无处不在。常见的例子包括

  • 点和向量
  • 日期和日期差异
  • 文件和差异

  • 等等。

    Haskell的一种可能定义是:
     class Torsor a where
        type TorsorOf a :: *
        (.-) :: a -> a -> TorsorOf a
        (.+) :: a -> TorsorOf a -> a
    

    以下是一些示例实例:
     instance Torsor UTCTime where
        type TorsorOf UTCTime = NominalDiffTime
        a .- b = diffUTCTime a b
        a .+ b = addUTCTime b a
    
     instance Torsor Double where
        type TorsorOf Double = Double
        a .- b = a - b
        a .+ b = a + b
    
    instance Torsor Int where
        type TorsorOf Int = Int
        a .- b = a - b
        a .+ b = a + b
    

    在最后一种情况下,请注意,两组扭力不必是不同的扭力,这使得将相对值加在一起很简单。

    有关更多信息,请参见a much nicer description in Roman Cheplyakas blog

    09-04 19:18