哈斯克尔:限制" a"某些类型?

时间:2014-10-16 17:41:15

标签: haskell types tuples

我有一棵树,旨在在每个节点包含一个元组:

-- 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 个答案:

答案 0 :(得分:9)

是。您可以使用广义代数数据类型(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

答案 1 :(得分:4)

如果你改为写

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

您可以保证节点中将包含相同类型的元组。这不是你要求的,但可能就是你真正需要的。当然它简化了问题:现在你只需要将a限制为Int或Float,而不是它们的元组,如果这真的是你需要的那样。