具有约束 return 类型的类型类实例
Typeclass instances with constrained return type
我正在实现一个内积的概念,它在容器和数字类型上是通用的。定义指出此操作的 return 类型是(非负)实数。
一种选择(如下所示)是为每种数值类型(Float、Double、Complex Float、Complex Double、Complex CFloat、Complex CDouble 等)手动编写所有实例。原始类型不多,但我不喜欢重复。
另一种选择,或者我认为,是有一个带有约束的参数实例,例如 RealFloat
(代表 Float
和 Double
)。
{-# language MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}
module Test where
import Data.Complex
class Hilbert c e where
type HT e :: *
dot :: c e -> c e -> HT e
instance Hilbert [] Double where
type HT Double = Double
dot x y = sum $ zipWith (*) x y
instance Hilbert [] (Complex Double) where
type HT (Complex Double) = Double
a `dot` b = realPart $ sum $ zipWith (*) (conjugate <$> a) b
问题
为什么下面的实例不起作用 ("Couldn't match type e
with Double
.. expected type HT e
, actual type e
")?
instance RealFloat e => Hilbert [] e where
type HT e = Double
dot x y = sum $ zipWith (*) x y
嗯,那个特定的实例不起作用,因为 sum
只产生一个 e
,但你希望结果是 Double
。由于 e
被 限制为 RealFrac
,这很容易解决,因为任何 Real
(尽管在数学上有问题)都可以转换为一个 Fractional
:
dot x y = realToFrac . sum $ zipWith (*) x y
但是,该通用实例会阻止您同时定义复杂实例:使用 instance RealFloat e => Hilbert [] e where
可以涵盖 所有 类型,即使它们不是真正的实数。您仍然可以将 Complex
实例化为重叠实例,但如果可以的话,我宁愿远离它们。
是否应该在 * -> *
上定义这样的向量空间 类 也值得怀疑。是的,linear
also does it this way, but IMO parametricity doesn't work in our favour in this application. Have you checked out the vector-space
package? Mind, it isn't exactly complete for doing serious linear algebra; that's a gap I hope to fill with my linearmap-category
package.
我正在实现一个内积的概念,它在容器和数字类型上是通用的。定义指出此操作的 return 类型是(非负)实数。
一种选择(如下所示)是为每种数值类型(Float、Double、Complex Float、Complex Double、Complex CFloat、Complex CDouble 等)手动编写所有实例。原始类型不多,但我不喜欢重复。
另一种选择,或者我认为,是有一个带有约束的参数实例,例如 RealFloat
(代表 Float
和 Double
)。
{-# language MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}
module Test where
import Data.Complex
class Hilbert c e where
type HT e :: *
dot :: c e -> c e -> HT e
instance Hilbert [] Double where
type HT Double = Double
dot x y = sum $ zipWith (*) x y
instance Hilbert [] (Complex Double) where
type HT (Complex Double) = Double
a `dot` b = realPart $ sum $ zipWith (*) (conjugate <$> a) b
问题
为什么下面的实例不起作用 ("Couldn't match type e
with Double
.. expected type HT e
, actual type e
")?
instance RealFloat e => Hilbert [] e where
type HT e = Double
dot x y = sum $ zipWith (*) x y
嗯,那个特定的实例不起作用,因为 sum
只产生一个 e
,但你希望结果是 Double
。由于 e
被 限制为 RealFrac
,这很容易解决,因为任何 Real
(尽管在数学上有问题)都可以转换为一个 Fractional
:
dot x y = realToFrac . sum $ zipWith (*) x y
但是,该通用实例会阻止您同时定义复杂实例:使用 instance RealFloat e => Hilbert [] e where
可以涵盖 所有 类型,即使它们不是真正的实数。您仍然可以将 Complex
实例化为重叠实例,但如果可以的话,我宁愿远离它们。
是否应该在 * -> *
上定义这样的向量空间 类 也值得怀疑。是的,linear
also does it this way, but IMO parametricity doesn't work in our favour in this application. Have you checked out the vector-space
package? Mind, it isn't exactly complete for doing serious linear algebra; that's a gap I hope to fill with my linearmap-category
package.