(为这个怪异的标题表示歉意,但我想不出更好的标题了。)
对于个人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。