[英]Haskell - GeneralizedNewtypeDeriving pragma's interaction with constraints and datatypes
This is a question arising from my code at:这是我的代码引起的问题:
Haskell - Creating constraints and applying to datatypes Haskell - 创建约束并应用于数据类型
{-# 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?我对
GeneralizedNewtypeDeriving
pragma 的使用是否正确? 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.我原本打算让
Identity a
Num a
特征,而无需为NewConstraint
设置Num a
约束实例,但它没有用。 Is this approach possible?这种方法可行吗? Where did I go wrong?
我哪里做错了?
UPDATE on 30 June 2021 2021 年 6 月 30 日更新
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 #-}
.它无需
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
。 When is the pragma needed?什么时候需要编译指示?
The instance of Num
derived via GeneralizedNewtypeDeriving
for Identity
has the form:通过
GeneralizedNewtypeDeriving
for Identity
派生的Num
实例具有以下形式:
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;也就是说,如果包装类型
X
在Num
,那么你可以写1 :: X
,那么Identity X
也在Num
,所以你也可以写1 :: Identity X
; similarly, you can use the Num
arithmetic operators:同样,您可以使用
Num
算术运算符:
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
.因此,您可以只写
Identity 1
,而不是通过默认Num a => a
到Integer
来编写具有Identity Integer
类型的Identity Integer
1
。 For illustration, if you remove the ambiguous Num a
& NewConstraint a
constraints from the NewConstraint (Identity a)
instance, then you can write:例如,如果您从
NewConstraint (Identity a)
实例中删除不明确的Num a
& NewConstraint a
约束,那么您可以编写:
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
:或者,使用
PartialTypeSignatures
语言选项,您可以省略内部注释,它将包装类型默认为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.在这种特殊情况下,您需要一些注释,原因与在
show (read "123")
需要注释show (read "123")
原因相同:您需要确定read :: Read a => String -> a
和show :: Show a => a -> String
重载show :: Show a => a -> String
你正在调用的show :: Show a => a -> String
。 In this case, you have fromInteger :: Num a => Integer -> a
implicitly due to the number literal, and getTrue :: NewConstraint a => a -> Bool
.在这种情况下,由于数字文字,您有
fromInteger :: Num a => Integer -> a
隐式,以及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.您必须至少指定
a
= Identity b
,因此类型Num b => b
仍然不明确,但Num
可以是默认值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.