10

Real World Haskellの 321 ページ

これらのコードがあり、

...

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype AInt = A { unA::Int }
    deriving (Show, Eq, Num)

instance Monoid AInt where
    mempty = 0

私の混乱はなぜそれが

mempty = 0

だがしかし

mempty = A 0

?


また、両方に気付きました

ghci> 0 :: AInt

ghci> A 0 :: AInt

同じ返事をして

A { unA = 0 }

これら2つの違いは何ですか?

4

2 に答える 2

14

ここでの秘訣はGeneralizedNewtypeDeriving拡張機能です。特に、これにより、基になる型がインスタンスである限り、任意のクラスを派生させることができます。newtypeこれが行うのは、インスタンスを古いタイプから新しいタイプにコピーすることだけです。

この特定のケースでは、 をAInt派生させNumます。これは、 と同じコードを使用AIntするインスタンスであることを意味します (必要に応じてすべてがコンストラクターにラップされています)。これにはの機能が含まれます。NumIntAIntfromInteger

fromInteger関数はInt'sで定義され、次のfromIntegerようになります。

fromInteger i = A (fromInteger i)

0はポリモーフィックであるため (型を持っています) 、 の任意の型0 :: Num a => aに対して有効な定数です。newtype の派生のおかげで、これには上記の関数を使用したが含まれます。これは、 と の間に違いがないことを意味します。NumAIntfromInteger0 :: AIntA 0 :: AInt

于 2013-04-16T04:31:39.640 に答える
12

のような数値リテラル0はオーバーロードされ、型を持ちます。これは、コンテキストに応じて0 :: Num a => a、インスタンスが存在する任意の型にすることができることを意味します。これは型クラスの関数をNum介して行われるため、入力すると、.fromIntegerNum0fromInteger 0

を使用することGeneralizedNewtypeDerivingで、GHC は (事実上1 )Numクラスのインスタンスを次のように記述します。

instance Num AInt where
  fromInteger n = A (fromInteger n)
  ...

したがって、 を書くと、これは (上記の定義により) which is (上記の定義により) に0 :: AInt展開され、 which は と同じになります。fromInteger 0 :: AIntA (fromInteger 0)A 0

1 GeneralizedNewtypeDerivingは実際には新しいインスタンスを作成しません。既存のものを使用するために必要なキャストを実行するだけです。

于 2013-04-16T04:31:15.580 に答える