2012-04-28 9 views
1

私のプログラムで型の安全性を高めるために、いくつかのバージョンのものを定義したいが、異なる型を定義したいと思う。たとえば、私はNumのインスタンスになりたいいくつかの二変量値を持っていますが、すべてが異なるタイプでなければなりません。だから、私がやったことは、1つの型変数を持つnewtypeを作成し、それに基づいて新しい型を宣言することです。しかし、私は今、両方のコンストラクタを常に使用しなければならないというのは、ちょっと面倒です。これを回避する方法はありますか?Haskell:型セーフな同義語用のnewtype:2つのコンストラクタを使用していますか?

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

newtype Bivar t = Bivar (t,t) deriving (Show, Eq) 

instance (Num t) => Num (Bivar t) where 
    (+) (Bivar (x1,y1)) (Bivar (x2,y2)) = Bivar (x1+x2, y1+y2) 
    (-) (Bivar (x1,y1)) (Bivar (x2,y2)) = Bivar (x1-x2, y1-y2) 
    (*) (Bivar (x1,y1)) (Bivar (x2,y2)) = Bivar (x1*x2, y1*y2) 
    abs (Bivar (x1,y1)) = Bivar (abs x1, abs y1) 
    fromInteger i = Bivar (fromInteger i, fromInteger i) 
    signum (Bivar (x1,y1)) = Bivar (signum x1, signum y1) 

newtype BivarNode = BivarNode (Bivar Int) deriving (Show, Eq, Num) 
newtype BivarVal = BivarVal (Bivar Double) deriving (Show, Eq, Num) 
newtype HBivarVal = HBivarVal (Bivar Double) deriving (Show, Eq, Num) 

-- This is annoying: 
a1 = BivarVal (Bivar (1.0, 2.0)) 
a2 = HBivarVal (Bivar (1.0, 2.0)) 
b = BivarNode (Bivar (1,2)) 

-- is there a way so that I can write it this way? 
aa1 = BivarVal (1.0, 2.0) 
aa2 = HBivarVal (1.0, 2.0) 
bb = BivarNode (1,2) 

ありがとう!

EDIT:

元の質問に展開するには、私も、パターンの型の名前を使用したいと一致し、

myFunction :: HBivarVal -> Double 
myFunction (HBivarVal (Bivar (x,y))) = x 

の線に沿って何かがあまりにも可能ですか?

+6

2番目の質問には、ビューパターンを使用します。 –

+0

@ ThomasM.DuBuissonありがとう、それをチェックします – Paul

+1

新しいタイプのラッピングペアは実際にあなたに何も得られません(GHCはnewtypeラッパーを最適化しますが、すべてのパターンマッチングはまだペアを使用する必要があります)ので、 'data Bivar t = Bivar ttは同等で、キーストロークはわずかです... –

答えて

2

なぜさえそれらのすべてのnewtype、Bivarを作ってみませんか?

instance (Num a, Num b) => Num (a, b) where 
    (a, b) + (a', b') = (a+a', b+b') 
    (a, b) * (a', b') = (a*a', b*b') 
    (a, b) - (a', b') = (a-a', b-b') 
    fromInteger i = (fromInteger i, fromInteger i) 
    abs (a, b) = (abs a, abs b) 
    signum (a, b) = (signum a, signum b) 

newtype Bivar t = Bivar  (t  , t ) deriving (Show, Eq, Num) 
newtype BivarNode = BivarNode (Int , Int ) deriving (Show, Eq, Num) 
newtype BivarVal = BivarVal (Double, Double) deriving (Show, Eq, Num) 
newtype HBivarVal = HBivarVal (Double, Double) deriving (Show, Eq, Num) 
+1

'Num(a、b)'に孤立したインスタンスを追加しない場合は、代わりに(module-local、 "helper")データ型 'data pair a b = a:* b'を定義することができます。モジュールユーザーは知る必要はありません。 – luqui

+0

'GeneralizedNewtypeDeriving'コンパイラ拡張が必要です。 – luqui

+0

ありがとう、私はそれが私が探していた答えだと思います。私はNumインスタンスを宣言するための型が必要だと思った。 – Paul

1

はい、あなたはヘルパー関数を定義することができます。

bivarVal = BivarVal . Bivar 
hBivarVal = HBivarVal . Bivar 
bivarNode = BivarNode . Bivar 
+0

ありがとう!パターンマッチングでもこのようなものを使って元の値にする方法はありますか? – Paul

+0

いいえ、少なくとも、書かれているとおりではありません。任意の関数ではなく、コンストラクタでのみパターンマッチングできます。 – huon

+0

ええ、私は知っています。私は値に到達するために分解関数を組み合わせることができますが、まだパターンマッチングに役立たないafaik ... – Paul

関連する問題