haskell - How can I reuse a class instance for a newtype? -
i have defined type called natural
positive integer includes 0:
newtype natural = natural integer deriving (eq, ord) instance show natural show (natural i) = show tonatural :: (integral i) => -> natural tonatural x | x < 0 = error "natural cannot negative" | otherwise = natural $ tointeger x fromnatural :: natural -> integer fromnatural (natural i) = instance num natural frominteger = tonatural x + y = tonatural (fromnatural x + fromnatural y) x - y = let r = fromnatural x - fromnatural y in if r < 0 error "subtraction yielded negative value" else tonatural r x * y = tonatural (fromnatural x * fromnatural y) abs x = x signum x = tonatural $ signum $ fromnatural x instance enum natural toenum = tonatural . tointeger fromenum = frominteger . fromnatural
in code common newtype
s take natural
parameter. , since want these types instances of num
, enum
, find myself reimplementing same classes on , over:
newtype nodeid = nodeid natural deriving (show, eq, ord) instance num nodeid 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 toenum = nodeid . toenum fromenum (nodeid x) = fromenum x ... newtype instructionid = instructionid natural deriving (show, eq) instance num instructionid 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 toenum = instructionid . toenum fromenum (instructionid x) = fromenum x ... newtype patternid = patternid natural deriving (show, eq) instance num patternid 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 toenum = patternid . toenum fromenum (patternid x) = fromenum x
as see these implementations identical, made me wonder whether implement class a
implement num
, enum
classes, , each newtype
need implement simple function (maybe not function @ all) of a
. i'm not sure how or whether it's possible @ all.
any ideas?
there's extension called generalizednewtypederiving can use same end. lets "carry over" definitions underlying type newtype.
here's small, contrived code example:
{-# language generalizednewtypederiving #-} newtype foo = foo integer deriving (show, eq, num)\
it's bit confusing though: standard derived classes show
, eq
still derived normal way. foo
's show
instance different integer
's. however, other classes carried through directly, foo
's num
instances same integer
's.
you have little careful because does not play well haskell extensions. however, simple num
case, it's option. believe upcoming versions of ghc fixing of common problems generalizednewtypederiving
, should become safer extension in near future.
Comments
Post a Comment