Haskell 通过GeneraledNewTypeDeriving派生实例时使用自定义实例

Haskell 通过GeneraledNewTypeDeriving派生实例时使用自定义实例,haskell,ghc,typeclass,Haskell,Ghc,Typeclass,假设我们有一个typeclass类(aa,ba)=>ca其中。使用newtype将允许我们克隆数据类型,然后通过generalizednewtypedering语言自动派生实例 扩展(请参阅和) 问题:是否可以让ghc自动派生A和C,但在派生C时使用我们自己指定的B实现 例如,以下代码(其中A=Planet,B=存在着,C=说明)无法按预期工作: {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE StandaloneDeriving

假设我们有一个typeclass
类(aa,ba)=>ca其中
。使用
newtype
将允许我们克隆数据类型,然后通过
generalizednewtypedering
语言自动派生实例 扩展(请参阅和)

问题:是否可以让ghc自动派生
A
C
,但在派生
C
时使用我们自己指定的
B
实现

例如,以下代码(其中
A
=
Planet
B
=
存在着
C
=
说明
)无法按预期工作:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
module Main (main) where

data Cat = Cat String
newtype Dolphin = Dolphin Cat deriving (Planet)

------------------------------------------------

class Planet a where
  planet :: a -> String

class Lives a where
  lives :: a -> String

class (Planet a, Lives a) => Description a where
  description :: a -> String

------------------------------------------------

instance Planet Cat where
  planet _ = "lives on planet earth,"

instance Lives Cat where
  lives _ = "lives on land"

instance Description Cat where
  description a = (planet a) ++ (lives a)

------------------------------------------------

instance Lives Dolphin where
  lives _ = "lives in the sea"

--want the following derivation to use the instance of 
--"Lives" for "Dolphin" above
deriving instance Description Dolphin

------------------------------------------------

main = do
  print $ description (Cat "test")
  -- > "lives on planet earth,lives on land"
  -- OK
  print $ description (Dolphin (Cat "test"))
  -- > "lives on planet earth,lives on land"
  -- NOT OK. Want "lives on planet earth,lives in the sea"
我期望/想要的是在
Description
的派生中调用
lifes
Dolphin
实例

显然,以下程序可以工作,但它需要为
海豚
显式实例化
说明

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
module Main (main) where

data Cat = Cat String
newtype Dolphin = Dolphin Cat deriving (Planet)

------------------------------------------------

class Planet a where
  planet :: a -> String

class Lives a where
  lives :: a -> String

class (Planet a, Lives a) => Description a where
  description :: a -> String

------------------------------------------------

instance Planet Cat where
  planet _ = "lives on planet earth,"

instance Lives Cat where
  lives _ = "lives on land"

instance Description Cat where
  description a = (planet a) ++ (lives a)

------------------------------------------------

instance Lives Dolphin where
  lives _ = "lives in the sea"

instance Description Dolphin where
  description a = (planet a) ++ (lives a)

------------------------------------------------

main = do
  print $ description (Cat "test")
  -- > "lives on planet earth,lives on land"
  --[OK]
  print $ description (Dolphin (Cat "test"))
  -- > "lives on planet earth,lives in the sea"
  --[OK]
p、 令人困惑的是,如果(在第一个程序中)我没有声明:

instance Lives Dolphin where
  lives _ = "lives in the sea"
然后ghc抱怨:

Main.hs:36:1:
    No instance for (Lives Dolphin)
      arising from the superclasses of an instance declaration
    In the instance declaration for ‘Description Dolphin’

奇怪的是,ghc会抱怨没有
实例,如果
没有
描述
的(自动)派生过程中使用
实例,则
实例将
用于
海豚考虑以下几点:

newtype ProcessID = PID Int deriving Eq
这样做的目的是编写一个

instance Eq PID where
  (PID x) == (PID y)    =    x == y
换句话说,当您在
PID
上调用
=
时,它会将其展开为普通的
Int
,然后对其执行
=

我想,
派生实例描述Dolphin
也在做同样的事情;将
Dolphine
展开为
Cat
,然后对其调用
description
方法。这根本不是你想要的

问题:如果
description
的定义总是相同的,为什么它需要是一个类?为什么不能定义一个常规函数来实现这一点


(或者这是您想要解决的更复杂问题的简化?

将海豚解包成猫,然后调用该猫的描述方法:
:如果发生这种情况,ghc将不使用
实例生活海豚在哪里
(而是使用
实例生活猫在哪里
)。那么,如果第一个程序中没有这个
实例,ghc为什么会抱怨呢?
问题:如果描述的定义总是相同的,为什么它需要是一个类呢?为什么不能定义一个常规函数来实现这一点呢?
-这只是我所想到的一种情况的简化。实际上,我想象有一个复杂类型的类继承,并且我想修改一个实例的行为(对于给定类型)在该类型类的HealCracy的中间,而不必声明一个新的类型并重新声明所有的实例,只修改一个实例。理想情况下,我只声明修改过的实例。