让一个typeclass实例自动成为另一个实例 [英] Make a typeclass instance automatically an instance of another
问题描述
我想实现的是以下类的任何实例( SampleSpace
)应自动成为 Show $的实例c $ c>,因为
SampleSpace
包含创建字符串表示所需的整个接口,因此该类的所有可能实例都几乎相同。
What I'd like to achieve is that any instance of the following class (SampleSpace
) should automatically be an instance of Show
, because SampleSpace
contains the whole interface necessary to create a String representation and hence all possible instances of the class would be virtually identical.
{-# 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的well:
Since, as I found out already, while matching instance declarations GHC only looks at the head, and not at contraints, and so it believes Show (s a)
is about Rational as well:
[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
问题:是否有可能(通过启用重叠实例)使类型类型的任何实例自动成为另一个类型的实例?
Question: is it possible (otherwise than by enabling overlapping instances) to make any instance of a typeclass automatically an instance of another too?
推荐答案
tl; dr :不要这样做,或者,如果您坚持使用 -XOverlappingInstances
。
tl;dr: don't do that, or, if you insist, use -XOverlappingInstances
.
- 这不是
显示
class就在那里。Show
仅用于显示纯数据,实际上是以Haskell代码的形式显示,并且可以再次使用,从而生成原始值。 -
SampleSpace
应该不是首要的类。它似乎基本上是类型的类,它们具有类似于映射与它们相关联的Rational c>的类。为什么不在简单的
data
类型中使用它作为字段? - 即使我们接受设计......这样的通用
显示
实例(或者实际上,任何单参数类的泛型实例)在有人为具体类型创建另一个实例时遇到问题–在Show
的情况下,当然已经有很多实例了。那么编译器应该如何决定使用哪个实例呢? GHC可以这样做,事实上:如果打开-XOverlappingInstances
扩展名,它将选择更具体的扩展名(即instance SampleSpace s => ; Show(sa)
被任何更具体的实例覆盖),但实际上这并不像看起来那么微不足道 - 如果有人定义了另一个这样的泛型实例呢?至关重要的是:Haskell类型类始终是开放的,即基本上编译器必须假定所有类型都可能在任何类中。只有当特定的实例被调用时,它实际上需要这种证明,但它永远不会证明某类中的不是类型。
- This is not what the
Show
class is there for.Show
is for simply showing plain data, in a way that is actually Haskell code and can be used as such again, yielding the original value. SampleSpace
should perhaps not be a class in the first place. It seems to be basically the class of types that have something likeMap a Rational
associated with them. Why not just use that as a field in a plaindata
type?- Even if we accept the design... such a generic
Show
instance (or, indeed, generic instance for any single-parameter class) runs into problems when someone makes another instance for a concrete type – in the case ofShow
, there are of course already plenty of instances around. Then how should the compiler decide which of the two instances to use? GHC can do it, in fact: if you turn on the-XOverlappingInstances
extension, it will select the more specific one (i.e.instance SampleSpace s => Show (s a)
is “overridden” by any more specific instance), but really this isn't as trivial as may seem – what if somebody defined another such generic instance? Crucial to recall: Haskell type classes are always open, i.e. basically the compiler has to assume that all types could possibly in any class. Only when a specific instance is invoke will it actually need the proof for that, but it can never proove that a type isn't in some class.
我建议改为–因为 Show 实例并不仅仅显示数据,它应该变成一个不同的函数。无论是
What I'd recommend instead – since that Show
instance doesn't merely show data, it should be made a different function. Either
showDistribution :: (SampleSpace s, Show a, Ord a) => s a -> String
或甚至是
or indeed
showDistribution :: (Show a, Ord a) => SampleSpace a -> String
其中 SampleSpace
是一个具体类型,而不是一个班级。
where SampleSpace
is a single concrete type, instead of a class.
这篇关于让一个typeclass实例自动成为另一个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!