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

.

+3


source to share


1 answer


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?)

+2


source







All Articles