假设我们有一个类型类 class (A a, B a) => C a where
. 使用 newtype
将允许我们克隆数据类型,然后通过 GeneralizedNewtypeDeriving
语言扩展自动派生实例(请参阅how to write a derivable class?和Handling multiple types with the same internal representation and minimal boilerplate?) .
QUESTION :是否有可能让ghc自动派生 A
和 C
,但是在派生 C
时使用我们自己指定的 B
实现?
例如,以下代码(其中 A
= Planet
, B
= Lives
, C
= 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
的 Dolphin
实例在 Description
的派生中被调用 .
显然以下程序有效,但它需要一个为 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]
附:令人费解的是,如果(在第一个程序中)我没有声明:
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
如果 not 在 Description
的 Description
(自动)推导中使用 not .
1 回答
考虑以下:
这样做是写一个看起来像的实例
换句话说,当你在
PID
上调用==
时,它会将其解包为普通的Int
,然后对其执行==
.我想
deriving instance Description Dolphin
完全一样;将Dolphine
展开到Cat
中,然后在其上调用description
方法 . 哪个不是你想要的!问题:如果
description
的定义始终相同,为什么它必须是一个类?你为什么不能定义一个这样做的常规函数?(或者这是您要解决的一些更复杂问题的简化?)