用GADT构造类型类的具体类型

afu*_*ous 2 haskell typeclass gadt

这样做的灵感来自于创建一个值列表Show.我找到了以下使用GADT创建具体Showable类型的代码片段.

data Showable where Showable :: Show a => a -> Showable

instance Show Showable where
    show (Showable x) = show x

list :: [Showable]
list = [Showable 4, Showable "hello", Showable 'a']
Run Code Online (Sandbox Code Playgroud)

然后,我尝试Showable通过创建一个可以使任何类型类具体的类型来更加通用.

data Concrete a where Concrete :: a b => b -> Concrete a

instance Show (Concrete Show) where
    show (Concrete x) = show x

list :: [Concrete Show]
list = [Concrete 4, Concrete "hello", Concrete 'a']
Run Code Online (Sandbox Code Playgroud)

这适用于ConstraintKinds和FlexibleInstances语言扩展,但为了使用Concrete其他类型类的具体类型,每个类型都需要一个新实例.

有没有办法创建类似的东西Concrete,例如,Concrete Show自动是一个实例Show

chi*_*chi 6

这不可能.考虑一下:

instance Monoid (Concrete Monoid) where
   mappend (Concrete x) (Concrete y) = Concrete (mappend x y) -- type error!
Run Code Online (Sandbox Code Playgroud)

这是一种类型错误x,y来自两种不同的存在量化.无法保证x并且y可以加在一起.

换句话说,[Concrete [1,2], Concrete ["hello"]]有类型[Concrete Monoid]但不能求和(mconcat).


这正是同样的问题,在OOP中,以下基类/接口不起作用:

interface Vector {
   Vector scale(double x);
   Vector add(Vector v);
}
class Vec2D implements Vector { ... }
class Vec3D implements Vector { ... }
Run Code Online (Sandbox Code Playgroud)

界面意味着2D矢量可以添加到任何其他矢量,包括3D矢量,这是没有意义的.对于OOP解决方案,请参阅F-bounded量化及其相关推广,称为奇怪的重复模板模式.

在Haskell中,我们通常不需要这样的技术,因为没有子类型,因此类型类中的两种类型Vector已经不可混合.

class Vector a where
   scale :: Double -> a -> a
   add :: a -> a -> a
instance Vector (Vec2D) where ...
instance Vector (Vec3D) where ...
Run Code Online (Sandbox Code Playgroud)

  • 所以这就是为什么在Java中,它是`Thing实现Comparable <Thing>`而不仅仅是`Thing实现Comparable`.这是一个很好的答案. (3认同)