让一个typeclass实例自动成为另一个实例 [英] Make a typeclass instance automatically an instance of another

查看:169
本文介绍了让一个typeclass实例自动成为另一个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现的是以下类的任何实例( SampleSpace )应自动成为 Show ,因为 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.


  1. 这不是显示 class就在那里。 Show 仅用于显示纯数据,实际上是以Haskell代码的形式显示,并且可以再次使用,从而生成原始值。

  2. SampleSpace 应该不是首要的类。它似乎基本上是类型的类,它们具有类似于映射与它们相关联的Rational c>的类。为什么不在简单的 data 类型中使用它作为字段?

  3. 即使我们接受设计......这样的通用显示实例(或者实际上,任何单参数类的泛型实例)在有人为具体类型创建另一个实例时遇到问题–在 Show 的情况下,当然已经有很多实例了。那么编译器应该如何决定使用哪个实例呢? GHC可以这样做,事实上:如果打开 -XOverlappingInstances 扩展名,它将选择更具体的扩展名(即 instance SampleSpace s => ; Show(sa)被任何更具体的实例覆盖),但实际上这并不像看起来那么微不足道 - 如果有人定义了另一个这样的泛型实例呢?至关重要的是:Haskell类型类始终是开放的,即基本上编译器必须假定所有类型都可能在任何类中。只有当特定的实例被调用时,它实际上需要这种证明,但它永远不会证明某类中的不是类型。

  1. 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.
  2. SampleSpace should perhaps not be a class in the first place. It seems to be basically the class of types that have something like Map a Rational associated with them. Why not just use that as a field in a plain data type?
  3. 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 of Show, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆