让一个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是一个单一的具体类型,而不是一个类。

    链接地址: http://www.djcxy.com/p/43513.html

    上一篇: Make a typeclass instance automatically an instance of another

    下一篇: Impredicative types vs. plain old subtyping