2017-04-03 28 views
2

私はData.IPからIPタイプのnewtypeエイリアスを作成しました:このnewtypeには正しいReadインスタンスが与えられていないのはなぜですか?

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

module IPAddress (IPAddress) where 

import Data.IP (IP) 
import Database.PostgreSQL.Simple.ToField 

newtype IPAddress = IPAddress IP 
    deriving (Read, Show) 

instance ToField IPAddress where 
    toField ip = toField $ show ip 

(私は孤児のインスタンスを作成せずにそれをToFieldのインスタンスを作りたかった。)

新しいタイプには見えませんしかし、それはやり方でReadをサポートします。このGHCiの転写産物では、与えられた文字列がIPAddressとしてIPと解釈ではなく、できることを確認できます。

*Main IPAddress> :m + Data.IP 
*Main IPAddress Data.IP> read "1.2.3.4" :: IP 
1.2.3.4 
*Main IPAddress Data.IP> read "1.2.3.4" :: IPAddress 
IPAddress *** Exception: Prelude.read: no parse 

挙動は関係なく、私が上GeneralizedNewtypeDerivingを持っているかどうか、同じです。 IPAddressReadのインスタンスがIPのインスタンスと一致しないのはなぜですか?

+1

Showインスタンスも同様に表示し、どのようなものであるかを確認してください。それは同じように読むでしょう。 – amalloy

+0

私が正しく理解している場合、 'deriving Read'によって生成されたインスタンスは、' IPAddress'が 'data'型の場合と全く同じように動作します – pyon

+0

@amalloy' IsString'を派生クラスのリストに追加しました。 '' 1.2.3.4 ":: IPAddress'を介して' 'IPAddress'を作成します。この値で 'show'を呼び出すと、' 'IPAddress 1.2.3.4 ''となります。実際に '' IPAddress 1.2.3.4 :: IPAddress'を読んで、私がしたいことをします。あなたはあなたのコメントを答えにするべきだと思います!私は 'IPAddress'でなぜ値を前置かなければならないのかについての説明が大好きです。 – bdesham

答えて

7

GHCは、型クラスのインスタンスを導出するための3つの機構を有している:クラス(EqOrdEnumBoundedReadの小さい、所定のセットのインスタンスを導出することができる

  • Haskellの標準に概説normal deriving mechanism、およびShow)。
    • 有効場合規格に記載されているクラスと同じように扱われるDeriveFunctorDeriveFoldableDeriveTraversable、及びDeriveLift拡張を用いて拡張することができる誘導することができるクラスのセット。
  • GeneralizedNewtypeDeriving、これはラップされた型のインスタンスに遅延するインスタンスを派生できます。
  • DeriveAnyClassです。これにより、クラスが空のインスタンス宣言に変換されます。

ここに問題があります。上記のメカニズムのうちの2つ以上を使用してインスタンスを派生させるシナリオを構築することは非常に簡単で、インスタンスは全く異なる可能性があります。あなたの例では、普通の派生ののnewtypeの派生の両方が適用できます。 DeriveAnyClassも有効にした場合は、それも適用される可能性があります。明確にするために

、GHCは、あなたがそれを上から下にしようとしており、変更することはできませんハードコーディングされたルールを使用しています。それを使用して、クラスは通常の導出メカニズムを使用して導出することができる場合

  1. DeriveAnyClassが有効になっている場合は、それを使用してください。
  2. GeneralizedNewtypeDerivingが有効で、宣言されたデータ型がnewtypeの場合は、それを使用します。

これは、DeriveAnyClassGeneralizedNewtypeDerivingを同時にオンにすることは実質的に無益であることに注意してください。何かがあれば、下の2つのルールを交換する必要がありますが、実際には変更することはできません。

Readは、通常の派生メカニズムを使用してインスタンスを派生できるクラスであるため、GHCはnewtype派生を使用する代わりにそのインスタンスを使用し、表示される動作を取得します。これはShowの方法と一貫しており、Showが出力にIPAddressを含むインスタンスを生成するため、Readは同じフォーマットに従って、Readの1つの法則を満たす必要があります。

GHCに特定の導出メカニズムを使用するように指示するメカニズムがあればいいですが、現在はありません。この場合、インスタンスを手作業で記述する必要があります。幸いにも、それほど難しくありません。

+1

「GHCに特定の導出メカニズムを使用するように指示するメカニズムがあればいいだろう」 [これはGHC 8.2にあります](https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DerivingStrategies)。 – Alec

+0

@Alecああ、私はそれについて知りませんでした!それは私がしばらくしたいと思っていた機能なので、聞くのはすばらしいことです。 –

関連する問題