gpt4 book ai didi

class - 如何为新类型重用类实例?

转载 作者:行者123 更新时间:2023-12-01 11:39:42 25 4
gpt4 key购买 nike

我定义了一个名为 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

在我的代码中,使用 Natural 作为参数的 newtype 很常见。因为我希望这些类型成为 NumEnum 的实例,所以我发现自己一遍又一遍地重新实现相同的类:

newtype NodeId
= NodeId Natural
deriving (Show, Eq, Ord)

instance Num NodeId where
fromInteger = NodeId . toNatural
(NodeId x) + (NodeId y) = NodeId (x + y)
(NodeId x) - (NodeId y) = NodeId (x - y)
(NodeId x) * (NodeId y) = NodeId (x * y)
abs (NodeId x) = NodeId (abs x)
signum (NodeId x) = NodeId (signum x)

instance Enum NodeId where
toEnum = NodeId . toEnum
fromEnum (NodeId x) = fromEnum x

...

newtype InstructionId = InstructionId Natural
deriving (Show, Eq)

instance Num InstructionId where
fromInteger = InstructionId . toNatural
(InstructionId x) + (InstructionId y) = InstructionId (x + y)
(InstructionId x) - (InstructionId y) = InstructionId (x - y)
(InstructionId x) * (InstructionId y) = InstructionId (x * y)
abs (InstructionId x) = InstructionId (abs x)
signum (InstructionId x) = InstructionId (signum x)

instance Enum InstructionId where
toEnum = InstructionId . toEnum
fromEnum (InstructionId x) = fromEnum x

...

newtype PatternId = PatternId Natural
deriving (Show, Eq)

instance Num PatternId where
fromInteger = PatternId . toNatural
(PatternId x) + (PatternId y) = PatternId (x + y)
(PatternId x) - (PatternId y) = PatternId (x - y)
(PatternId x) * (PatternId y) = PatternId (x * y)
abs (PatternId x) = PatternId (abs x)
signum (PatternId x) = PatternId (signum x)

instance Enum PatternId where
toEnum = PatternId . toEnum
fromEnum (PatternId x) = fromEnum x

如您所见,这些实现几乎相同,这让我想知道我是否可以实现某个类 A,它本身会实现 NumEnum 类,然后对于每个 newtype,我只需要实现 A 的一些简单功能(也许根本不是任何功能)。但我不确定该怎么做,或者它是否可能。

有什么想法吗?

最佳答案

有一个名为 GeneralizedNewtypeDeriving 的扩展您可以将其用于同一目的。它允许您将定义从基础类型“转移”到新类型。

这是一个人为设计的小代码示例:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

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

虽然有点困惑:标准派生类如 ShowEq 仍将以正常方式派生。所以 FooShow 实例不同于 Integer 的实例。但是,所有其他类都直接执行,因此 FooNum 实例与 Integer 的相同。

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

关于class - 如何为新类型重用类实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22603858/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com