2014-10-16 68 views
2

我打算包含在每個節點的元組樹:Haskell:將「a」限制爲某些類型?

-- Should be initialized with `a' as a tuple of (Int, Int) or (Float, Float) 
data MMTree a = Empty | Node a (MMTree a) (MMTree a) deriving Show 

有什麼辦法來限制a,使MMTree可以與特定類型的初始化;即(Int, Int)(Float, Float)而不是任何舊類型?

+2

創建一個私有類型類並僅爲這些類型實例化它。 – rightfold 2014-10-16 17:42:11

回答

8

是的。您可以使用廣義代數數據類型(GADT,http://en.wikibooks.org/wiki/Haskell/GADT),這些數據類型正是您所需要的(結果類型取決於所使用的構造函數)。作爲一個簡單的解決方案,可以使一個構造爲每個可能的節點類型:

{-# LANGUAGE GADTs #-} 

data MMTree a where 
    Empty :: MMTree a 
    NodeI :: (Int, Int) -> MMTree (Int, Int) -> MMTree (Int, Int) -> MMTree (Int, Int) 
    NodeF :: (Float, Float) -> MMTree (Float, Float) -> MMTree (Float, Float) -> MMTree (Float, Float) 

但是,這個方案是不是很好(因爲你需要添加更多的構造函數,如果以後你需要使用其他元素使用相同的樹型)。所以,DataKindsTypeFamilies救援:

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE TypeFamilies #-} 

data TreeType 
    = TInt 
    | TFloat 

type family Elem (t :: TreeType) where 
    Elem TInt = (Int, Int) 
    Elem TFloat = (Float, Float) 

data MMTree (t :: TreeType) where 
    Empty :: MMTree a 
    Node :: Elem a -> MMTree a -> MMTree a -> MMTree a 

test1 :: MMTree TInt 
test1 = Node (1, 1) Empty Empty 

test2 :: MMTree TFloat 
test2 = Node (2.0, 3.0) Empty Empty 

這是,如果你真的想在data聲明限制使用的類型的解決方案。不過,我想提出一個更簡單的解決方案:只需保留樹定義,並且如果您想要處理一個樹,其中節點預期包含數值的元組,則只需使用類型簽名來編寫函數:

someFun :: (Num a) => MMTree (a, a) -> r 
4

如果改爲寫

data MMTree a = Empty | Node (a, a) (MMTree a) (MMTree a) deriving Show 

可以保證節點都將在他們同一類型的元。這不完全是你要求的,但可能是你真正需要的。當然,它簡化了這個問題:現在你只需要將a限制爲Int或Float,而不是它們的元組,如果這真的是你需要的。

+2

除此之外,您可以將數據構造函數設爲私有,然後創建由模塊導出的智能構造函數。這些構造函數只允許在其中存儲'Num a =>(a,a)'值,即'empty :: Num a => MMTree a'和'node :: Num a =>(a, a) - > MMTree a - > MMTree a - > MMTree a',很像'Data.Map.empty'和'Data.Map.fromList'。 – bheklilr 2014-10-16 18:10:30

相關問題