This is a question arising from my code at:
Haskell - Creating constraints and applying to datatypes
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
class NewConstraint a where
getTrue :: a -> Bool
newtype Identity a = Identity a
deriving (Eq, Show, Num)
instance (Num a, NewConstraint a) =>
NewConstraint (Identity a) where
getTrue x = True
test :: Bool
test = getTrue (Identity 1)
Is my use of the GeneralizedNewtypeDeriving
pragma correct? I had intended for Identity a
to take on Num a
characteristics without doing up a Num a
constrained instance for NewConstraint
, but it didn't work. Is this approach possible? Where did I go wrong?
UPDATE on 30 June 2021
This is my current code:
class NewConstraint a where
getTrue :: a -> a
newtype Identity a = Identity a
deriving (Show)
instance NewConstraint (Identity a) where
getTrue x = x
-- test :: Identity Integer
test = getTrue (Identity 1)
It works without the need for {-# LANGUAGE GeneralizedNewtypeDeriving #-}
. When is the pragma needed?
The instance of Num
derived via GeneralizedNewtypeDeriving
for Identity
has the form:
instance (Num a) => Num (Identity a) where
fromInteger i = Identity (fromInteger i)
Identity x + Identity y = Identity (x + y)
-- …
-- Similar for ‘(-)’, ‘(*)’, ‘abs’, ‘negate’, ‘signum’.
-- …
That is, if the wrapped type X
is in Num
, so you can write 1 :: X
, then Identity X
is also in Num
, so you can write 1 :: Identity X
as well; similarly, you can use the Num
arithmetic operators:
x, y, z :: Identity Int
x = Identity 5
y = Identity 7
z = x * y -- == Identity 35
So instead of writing Identity 1
, which has the type Identity Integer
by the defaulting of Num a => a
to Integer
, you can write just 1
. For illustration, if you remove the ambiguous Num a
& NewConstraint a
constraints from the NewConstraint (Identity a)
instance, then you can write:
test :: Bool
test = getTrue (1 :: Identity Int)
Or, with the PartialTypeSignatures
language option, you can omit the inner annotation, which defaults the wrapped type to Integer
:
test = getTrue (1 :: Identity _)
You need some annotation in this particular case for the same reason that you need one in show (read "123")
: you need to determine which overload of read :: Read a => String -> a
and show :: Show a => a -> String
you're calling. In this case, you have fromInteger :: Num a => Integer -> a
implicitly due to the number literal, and getTrue :: NewConstraint a => a -> Bool
. You must specify at least that a
= Identity b
, whereupon the type Num b => b
is still ambiguous, but Num
can be defaulted.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.