Class 如何为新类型重用类实例?

Class 如何为新类型重用类实例?,class,haskell,Class,Haskell,我定义了一个名为Natural的类型,它是一个包含0的正整数: newtype Natural = Natural Integer deriving (Eq, Ord) instance Show Natural where show (Natural i) = show i toNatural :: (Integral i) => i -> Natural toNatural x | x < 0 = error "Natural cannot be ne

我定义了一个名为
Natural
的类型,它是一个包含0的正整数:

newtype Natural = Natural Integer
    deriving (Eq, Ord)
instance Show Natural where
  show (Natural i) = show i

toNatural :: (Integral i) => i -> Natural
toNatural x | x < 0     = error "Natural cannot be negative"
            | otherwise = Natural $ toInteger x

fromNatural :: Natural -> Integer
fromNatural (Natural i) = i

instance Num Natural where
    fromInteger = toNatural
    x + y       = toNatural (fromNatural x + fromNatural y)
    x - y       = let r = fromNatural x - fromNatural y in
                      if r < 0 then error "Subtraction yielded a negative value"
                               else toNatural r
    x * y       = toNatural (fromNatural x * fromNatural y)
    abs x       = x
    signum x    = toNatural $ signum $ fromNatural x

instance Enum Natural where
  toEnum = toNatural . toInteger
  fromEnum = fromInteger . fromNatural
正如您所看到的,这些实现几乎是相同的,这让我想知道是否可以实现一些类
A
,它本身可以实现
Num
Enum
类,然后对于每个
newtype
我只需要实现一些简单的函数(可能根本不需要任何函数)属于
A
。但我不知道该怎么做,也不知道这是否可能


有什么想法吗?

有一个扩展名为,可以用于相同的目的。它允许您将定义从基础类型“延续”到新类型

下面是一个小的人为代码示例:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Foo = Foo Integer deriving (Show, Eq, Num)\
不过,这有点令人困惑:标准派生类,如
Show
Eq
仍将以正常方式派生。所以
Foo
Show
实例不同于
Integer
。但是,所有其他类都直接执行,因此
Foo
Num
实例与
Integer
的实例相同


您必须对它小心一点,因为它具有某些Haskell扩展。但是,对于简单的
Num
情况,它是一个非常好的选择。我还相信,即将发布的GHC版本正在修复
GeneralizedNewtypeDeriving
的一些常见问题,因此在不久的将来它应该成为一个更安全的扩展。

酷!这删除了所有丑陋的重复代码=DGHC 7.8将具有修复GND漏洞的角色系统。特别是,它们从编译器错误变为库设计器错误库设计器必须选择其公开的类型是否应为GND-applicable。该类型应声明为
newtype Natural=Natural{unNatural::Integer}
。(对不起,无法抗拒;-))
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Foo = Foo Integer deriving (Show, Eq, Num)\