2012-04-28 30 views
1

我想定義一個事物的幾個版本,但是使用不同的類型來增強我的程序中的類型安全性。例如,我有幾種類型的雙變量值,我想要成爲Num的實例,但所有變量都應該是不同的類型。所以我所做的就是用一個類型變量創建一個新類型並基於此類型聲明新類型。然而,我覺得現在不得不一直使用這兩個構造函數,這有點令人討厭。有沒有辦法解決?Haskell:類型安全同義詞的新類型:使用兩個構造函數的任何方式?

{-# 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) 

謝謝!

編輯:

要在原來的問題擴大,我也想對模式匹配,沿

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

線的東西所用的類型名稱是可能的嗎?

+6

對於第二個問題:使用視圖模式。 – 2012-04-28 12:59:08

+0

@ ThomasM.DuBuisson謝謝你,請檢查一下 – Paul 2012-04-28 16:50:44

+1

Newtype包裝一對並沒有給你帶來什麼好處(雖然GHC會優化掉新包裝,但所有的模式匹配都必須使用這兩個包),所以數據Bivar t = Bivar tt'是等效的,並且按鍵次數略少... – 2012-04-28 17:55:41

回答

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)'添加一個孤立實例,你可以定義一個(模塊本地,「幫助」)數據類型'data Pair a b = a:* b'。模塊用戶甚至不需要知道。 – luqui 2012-04-29 07:30:50

+0

需要'GeneralizedNewtypeDeriving'編譯器擴展,我想。 – luqui 2012-04-29 07:32:00

+0

謝謝,我認爲那是我正在尋找的答案。我認爲我需要一個類型來聲明Num實例。 – Paul 2012-04-29 08:18:17

1

是的,你可以定義輔助功能:

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

謝謝!有沒有辦法在模式匹配中使用類似的東西來獲得原始值? – Paul 2012-04-28 12:52:24

+0

不,至少不是這樣寫的:你只能對構造函數進行模式匹配,而不能對任意函數進行模式匹配。 – huon 2012-04-28 12:54:19

+0

是的,我知道。我可以將解構函數結合起來以達到值,但afaik仍然不能幫助模式匹配... – Paul 2012-04-28 12:56:36

相關問題