使类型类实例自动成为另一个实例
Make a typeclass instance automatically an instance of another
我想要实现的是以下 class (SampleSpace
) 的任何实例都应自动成为 Show
的实例,因为 SampleSpace
包含创建字符串表示所必需的整个接口,因此 class 的所有可能实例实际上都是相同的。
{-# 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 (s a)
也是关于 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
问题:是否有可能(除非启用重叠实例)使一个类型的任何实例class 也自动成为另一个类型的实例?
tl;dr:不要那样做,或者,如果你坚持,使用 -XOverlappingInstances
.
- 这不是
Show
class 的目的。 Show
用于简单地显示纯数据,实际上是 Haskell 代码,可以再次使用,产生原始值。
SampleSpace
一开始也许不应该是 class。它似乎基本上是 class 类型与它们相关联的类似 Map a Rational
的类型。为什么不将其用作普通 data
类型中的字段?
- 即使我们接受设计...这样一个通用
Show
实例(或者,实际上,任何单参数 class 的通用实例)在有人为另一个实例创建另一个实例时会遇到问题一个具体的类型——在 Show
的情况下,当然已经有很多实例了。那么编译器应该如何决定使用这两个实例中的哪一个呢?事实上,GHC 可以做到:如果你打开 -XOverlappingInstances
扩展,它将 select 更具体的扩展(即 instance SampleSpace s => Show (s a)
被任何更具体的实例“覆盖”),但是实际上,这并不像看起来那么微不足道——如果有人定义了 another 这样的通用实例怎么办?重要的是要记住:Haskell 类型 classes 总是开放的 ,即基本上编译器必须假设 all 类型可能在任何 class。只有当一个特定的实例被调用时,它才真正需要证明,但它永远无法证明 不是 在某些 class. 中
我建议的是 - 因为 Show
实例不只是显示数据,所以它应该具有不同的功能。要么
showDistribution :: (SampleSpace s, Show a, Ord a) => s a -> String
或者确实
showDistribution :: (Show a, Ord a) => SampleSpace a -> String
其中 SampleSpace
是单个具体类型,而不是 class。
我想要实现的是以下 class (SampleSpace
) 的任何实例都应自动成为 Show
的实例,因为 SampleSpace
包含创建字符串表示所必需的整个接口,因此 class 的所有可能实例实际上都是相同的。
{-# 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 (s a)
也是关于 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
问题:是否有可能(除非启用重叠实例)使一个类型的任何实例class 也自动成为另一个类型的实例?
tl;dr:不要那样做,或者,如果你坚持,使用 -XOverlappingInstances
.
- 这不是
Show
class 的目的。Show
用于简单地显示纯数据,实际上是 Haskell 代码,可以再次使用,产生原始值。 SampleSpace
一开始也许不应该是 class。它似乎基本上是 class 类型与它们相关联的类似Map a Rational
的类型。为什么不将其用作普通data
类型中的字段?- 即使我们接受设计...这样一个通用
Show
实例(或者,实际上,任何单参数 class 的通用实例)在有人为另一个实例创建另一个实例时会遇到问题一个具体的类型——在Show
的情况下,当然已经有很多实例了。那么编译器应该如何决定使用这两个实例中的哪一个呢?事实上,GHC 可以做到:如果你打开-XOverlappingInstances
扩展,它将 select 更具体的扩展(即instance SampleSpace s => Show (s a)
被任何更具体的实例“覆盖”),但是实际上,这并不像看起来那么微不足道——如果有人定义了 another 这样的通用实例怎么办?重要的是要记住:Haskell 类型 classes 总是开放的 ,即基本上编译器必须假设 all 类型可能在任何 class。只有当一个特定的实例被调用时,它才真正需要证明,但它永远无法证明 不是 在某些 class. 中
我建议的是 - 因为 Show
实例不只是显示数据,所以它应该具有不同的功能。要么
showDistribution :: (SampleSpace s, Show a, Ord a) => s a -> String
或者确实
showDistribution :: (Show a, Ord a) => SampleSpace a -> String
其中 SampleSpace
是单个具体类型,而不是 class。