简体   繁体   English

Haskell - GeneralizedNewtypeDeriving pragma 与约束和数据类型的交互

[英]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;也就是说,如果包装类型XNum ,那么你可以写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 => aInteger来编写具有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 -> ashow :: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM