(为奇怪的标题道歉,但我想不出更好的标题。)
对于个人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
答案 0 :(得分:9)
我认为你正在寻找一个名为 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
在最后一种情况下,请注意两组扭转器不需要是不同的组,这使得将相对值加在一起变得简单。
答案 1 :(得分:8)
我认为你不应该试图统一这些运营商。减去两个向量并减去两个点是根本不同的操作。在类型系统中很难将它们表示为相同的事实并不是类型系统笨拙 - 这是因为这两个概念确实是不同的东西!
您正在使用的数学框架是affine space。
这些在Haskell的vector-space包中已经可用(在命令提示符下执行cabal install vector-space
)。它们不使用多参数类型类,而是使用类型族将矢量(相对)类型与每个点(绝对)类型相关联。
这是一个最小的例子,展示了如何定义自己的绝对和相对数据类型及其交互:
{-# LANGUAGE TypeFamilies #-}
import Data.VectorSpace
import Data.AffineSpace
data Point = Point { px :: Float, py :: Float }
data Vec = Vec { vx :: Float, vy :: Float }
instance AdditiveGroup Vec where
zeroV = Vec 0 0
negateV (Vec x y) = Vec (-x) (-y)
Vec x y ^+^ Vec x' y' = Vec (x+x') (y+y')
instance AffineSpace Point where
type Diff Point = Vec
Point x y .-. Point x' y' = Vec (x-x') (y-y')
Point x y .+^ Vec x' y' = Point (x+x') (y+y')
答案 2 :(得分:8)
你有两个答案告诉你应该做什么,这是另一个答案,告诉你如何做你要求的(这可能不是一个好主意)。 :)
class Add a b c | a b -> c where
(#+) :: a -> b -> c
instance Add AbsTime RelTime AbsTime where
(#+) = ...
instance Add RelTime RelTime RelTime where
(#+) = ...
(#+)
的重载使其非常灵活。太灵活了,IMO。唯一的限制是结果类型由参数类型决定(没有这个FD,操作符变得几乎无法使用,因为它没有任何约束)。