是的。您可以使用广义代数数据类型(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)
但是,这个方案是不是很好(因为你需要添加更多的构造函数,如果以后你需要使用其他元素使用相同的树型)。所以,DataKinds
和TypeFamilies
救援:
{-# 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
创建一个私有类型类并仅为这些类型实例化它。 – rightfold 2014-10-16 17:42:11