关于具有多态数据类型的类定义,我有一个问题。让我们说定义的数据类型是:
data BTree a = BLeaf a | BNode a (BTree a) (BTree a) deriving(Show)
假设我想要检索树根的值,但是在名为Tree的类的实例中:
class Tree a where
getRoot:: a -> (?) --<- Type of Leave value as return type
和一个实例:
instance Tree (BTree a) where
getRoot BLeaf a = a
getRoot BNode a _ _ = a
我无法弄清楚函数的类型(参见questionmark),因为它不是a而且类不知道实例的参数。
使class Tree
声明中的类型变量引用类型* -> *
的类型构造函数,然后您可以引用getRoot
类型签名中树的值的类型。
class Tree t where
getRoot :: t a -> a
instance Tree BTree where
getRoot (BLeaf a) = a
getRoot (BNode a _ _) = a
另一个稍微复杂的解决方案,允许树结构是善良的*
将是使用multi-parameter type class与functional dependencies。
{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}
class Tree t a | t -> a where
getRoot :: t -> a
instance Tree (BTree a) a where
getRoot (BLeaf a) = a
getRoot (BNode a _ _) = a
或者你可以使用type family。
{-# LANGUAGE TypeFamilies #-}
class Tree t where
type Value t
getRoot :: t -> Value t
instance Tree (BTree a) where
type Value (BTree a) = a
getRoot (BLeaf a) = a
getRoot (BNode a _ _) = a
首先,请记住,你的BTree
是一种类型的* -> *
,这基本上意味着它需要另一种类型作为参数来创建 - 你的a
。因此,将类的变量称为a
也会导致混淆。让我们换一下outer
来说明一点。
然后你有:
class Tree outer where
getRoot :: ???
寻找找到该函数的类型。知道树型需要另一种类型,我们知道getRoot
必须传递像BTree Int
这样的变量中的outer inner
。您希望函数返回具有该内部类型的内容,因此您的类将是:
class Tree outer where
getRoot :: outer inner -> inner
现在这是有道理的!您将树传递给该函数,它会向您显示具有该内部类型的内容。
然后,您将像以前一样实现您的实例:
instance Tree (BTree a) where
getRoot (BLeaf x) = x
getRoot (BNode x _ _) = x