Using a custom instance when getting an instance through GenerizedNewtypeDeriving
Let's assume we have a typeclass class (A a, B a) => C a where
. Usage newtype
will allow us to clone a datatype and then automatically infer instances through the GeneralizedNewtypeDeriving
extension language (see How to write a derived class? And Handling multiple types with the same internal representation and minimal template? ).
QUESTION : is it possible to get ghc to automatically get A
and C
, but use our own implementation B
in output C
?
For example, the following code (where A
= Planet
, B
= Lives
, C
= Description
) does not work as expected:
{-# 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"
I expected / wanted an instance to be Dolphin
Lives
called on output Description
.
Obviously, the following program works, but it requires you to explicitly instantiate it Description
for 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]
ps What is puzzling is that if (in the first program) I do not declare:
instance Lives Dolphin where
lives _ = "lives in the sea"
Then ghc complains:
Main.hs:36:1:
No instance for (Lives Dolphin)
arising from the superclasses of an instance declaration
In the instance declaration for ‘Description Dolphin’
It seems odd that ghc will complain about missing instance Lives Dolphin where
if not using it in (automatic) output Description
for Dolphin
.
source to share
Consider the following:
newtype ProcessID = PID Int deriving Eq
What it means is to write instances that look like
instance Eq PID where
(PID x) == (PID y) = x == y
In other words, when you call ==
in PID
, it unpacks it into a regular Int
one and then executes ==
.
I believe it deriving instance Description Dolphin
does the same; expanding a Dolphine
into Cat
and then calling the method description
. This is not at all what you want!
Question: If the definition is description
always the same, why should it be a class at all? Why can't you just define a regular function that does this?
(Or is this a simplification of another tricky problem you want to solve?)
source to share