Haskell:将"a"限制为某些类型?

Gov*_*mar 3 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
Run Code Online (Sandbox Code Playgroud)

有没有什么办法来限制a,这样MMTree可以与特定类型的初始化; 即,(Int, Int)或者(Float, Float)不是任何旧类型?

And*_*aev 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)
Run Code Online (Sandbox Code Playgroud)

但是,这个解决方案不是很好(因为如果以后你需要为其他元素使用相同的树类型,你需要添加更多的构造函数).所以,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
Run Code Online (Sandbox Code Playgroud)

如果您真的想在data声明中限制使用的类型,那么这就是解决方案.但是,我想建议一个更简单的解决方案:只保留树的定义,如果你想处理一个树,其中节点应该包含数值的元组,只需编写具有类型签名的函数:

someFun :: (Num a) => MMTree (a, a) -> r
Run Code Online (Sandbox Code Playgroud)