让一个typeclass实例自动成为另一个实例
我想要实现的是以下类( SampleSpace
)的任何实例都应该自动成为Show
一个实例,因为SampleSpace
包含创建String表示所需的整个接口,因此该类的所有可能实例都将几乎相同。
{-# LANGUAGE FlexibleInstances #-}
import Data.Ratio (Rational)
class SampleSpace space where
events :: Ord a => space a -> [a]
member :: Ord a => a -> space a -> Bool
probability :: Ord a => a -> space a -> Rational
instance (Ord a, Show a, SampleSpace s) => Show (s a) where
show s = showLines $ events s
where
showLines [] = ""
showLines (e:es) = show e ++ ": " ++ (show $ probability e s)
++ "n" ++ showLines es
因为,正如我已经发现的那样,虽然匹配的实例声明GHC只是看着头部,而不是有限制,所以它相信Show (sa)
也是关于Rational的:
[1 of 1] Compiling Helpers.Probability ( Helpers/Probability.hs, interpreted )
Helpers/Probability.hs:21:49:
Overlapping instances for Show Rational
arising from a use of ‘show’
Matching instances:
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
instance (Ord a, Show a, SampleSpace s) => Show (s a)
-- Defined at Helpers/Probability.hs:17:10
In the expression: show
In the first argument of ‘(++)’, namely ‘(show $ probability e s)’
In the second argument of ‘(++)’, namely
‘(show $ probability e s) ++ "" ++ showLines es
问题:是否有可能(通过启用重叠实例)使类型类型的任何实例自动成为另一个类型的实例?
tl; dr :不这样做,或者,如果你坚持,请使用-XOverlappingInstances
。
Show
类的用处。 Show
只是简单地显示纯数据,实际上是一种Haskell代码,可以再次使用它,从而产生原始值。 SampleSpace
应该不是SampleSpace
的类。 它似乎基本上是类型的类,它们具有像Map a Rational
与它们相关Map a Rational
的类。 为什么不把它用作普通data
类型的字段? Show
实例(或者实际上,任何单参数类的泛型实例)都会遇到问题 - 在Show
的情况下,当然已经有很多实例。 那么编译器应该如何决定使用哪个实例呢? GHC可以做到这一点,事实上:如果打开-XOverlappingInstances
扩展名,它将选择更具体的扩展名( instance SampleSpace s => Show (sa)
被更具体的实例重写),但实际上这是并不像看起来那么微不足道 - 如果有人定义了另一个这样的泛型实例呢? 至关重要的是:Haskell类型类总是开放的,即基本上编译器必须假定所有类型都可能在任何类中。 只有当一个特定的实例被调用时,它实际上需要这个证明,但它永远不会证明某个类不在某个类中。 我推荐的是 - 因为Show
实例不仅仅显示数据,它应该被做成不同的功能。 或
showDistribution :: (SampleSpace s, Show a, Ord a) => s a -> String
或确实如此
showDistribution :: (Show a, Ord a) => SampleSpace a -> String
SampleSpace
是一个单一的具体类型,而不是一个类。
上一篇: Make a typeclass instance automatically an instance of another