通过GeneralizedNewtypeDeriving获取实例时使用自定义实例

假设我们有一个类型class (A a, B a) => C a where 。 使用newtype将允许我们克隆一个数据类型,然后通过GeneralizedNewtypeDeriving语言扩展自动派生实例(请参阅如何编写可派生类?以及使用相同的内部表示形式处理多个类型以及最少的样板?)。

问题 :是否有可能让ghc自动派生AC ,而是使用我们自己的指定实现B来派生C

例如下面的代码(其中A = PlanetB = LivesC = Description )不能按预期工作:

{-# 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的派生中调用LivesDolphin实例。

很明显,下面的程序是可行的,但它需要明确实例化Dolphin Description

{-# 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]

ps令人费解的是,如果(在第一个程序中)我没有声明:

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会抱怨缺少instance Lives Dolphin where如果它没有DolphinDescription (自动)派生中使用它。


考虑以下:

newtype ProcessID = PID Int deriving Eq

这样做是写一个看起来像的实例

instance Eq PID where
  (PID x) == (PID y)    =    x == y

换句话说,当你在一个PID上调用==时,它将它解包到一个普通的Int ,然后执行==

我想象deriving instance Description Dolphin完全一样; 将DolphineDolphineCat ,然后调用description方法。 这不是你想要的!

问题:如果description的定义总是相同的,为什么它需要成为一个类? 为什么你不能只定义一个这样的常规函数​​?

(或者这是你想解决的一些更复杂问题的简化?)

链接地址: http://www.djcxy.com/p/7537.html

上一篇: Using custom instance when deriving an instance via GeneralizedNewtypeDeriving

下一篇: Are typeclasses essential?