3

typeclass があるとしますclass (A a, B a) => C a where。を使用すると、データ型を複製し、言語拡張機能newtypeを介してインスタンスを自動的に派生させることができます(派生可能なクラスを作成する方法と、同じ内部表現と最小限の定型文で複数の型を処理する方法を参照してください)。GeneralizedNewtypeDeriving

質問: ghc にAandを自動的に派生させることは可能ですが、派生Cに独自の指定された実装を使用することはできますか?BC

たとえば、次のコード ( 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"

私が期待/望んでいたのは、 のDolphinインスタンスがLivesの派生で呼び出されることでしDescriptionた。

明らかに、次のプログラムは機能しますが、明示的にインスタンス化する必要がありDescriptionます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不可解なのは、(最初のプログラムで) if を宣言していないことです:

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’

forの(自動)派生でそれを使用していないinstance Lives Dolphin where場合、 ghc が の不在について文句を言うのは奇妙に思えます。DescriptionDolphin

4

2 に答える 2

2

次の点を考慮してください。

newtype ProcessID = PID Int deriving Eq

これが行うことは、次のようなインスタンスを作成することです

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

つまり、==a を呼び出すとPID、通常の にラップ解除され、その上でInt実行==されます。

deriving instance Description Dolphinがまったく同じことをしていると思います。Dolphineaを aにアンラップし、そのメソッドをCat呼び出します。descriptionこれはあなたがまったく望んでいるものではありません!

質問: の定義descriptionが常に同じである場合、なぜクラスである必要があるのでしょうか? これを行う通常の関数を定義できないのはなぜですか?

(あるいは、これはあなたが解決したいもっと複雑な問題を単純化したものですか?)

于 2014-12-19T19:21:21.277 に答える
0

でこれが可能になりましたDerivingVia。最初に newtype ラッパーを定義します

newtype Describe a = Describe a
 deriving
 newtype (Planet, Lives)

instance (Planet a, Lives a) => Description (Describe a) where
  description :: Describe a -> String
  description a = planet a ++ lives a

Dolphin次に、 viaのインスタンスを派生させることができますDescribe Dolphin

{-# Language DerivingVia #-}

newtype Dolphin = Dolphin Cat
 deriving
 newtype Planet

 deriving Description
 via Describe Dolphin

今:

>> main
"lives on planet earth,lives on land"
"lives on planet earth,lives in the sea"
于 2021-06-26T12:43:14.487 に答える