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)\