Haskell 将数据、类型和函数绑定在一起
我想对一棵规则结构的大树(或森林)建模——树可以分解为小树(不规则部分)和(即)大参数列表,每个参数和每个节点构成一个大树节点 所以,我想要一个数据结构,其中树中的每个节点代表许多节点。而实际节点的类型为(node,param) 对于处理这类树的算法,param不会对其进行筛选。它们只是占位符。但是一些数据应该可以从普通参数或节点和参数的组合中提取,并且所有可能的参数都应该是可匹配的。所有这些类型的数据都是先验的,它们反映了树的语义 所以,param的实际类型、语义和内容取决于树的实现Haskell 将数据、类型和函数绑定在一起,haskell,typeclass,type-families,Haskell,Typeclass,Type Families,我想对一棵规则结构的大树(或森林)建模——树可以分解为小树(不规则部分)和(即)大参数列表,每个参数和每个节点构成一个大树节点 所以,我想要一个数据结构,其中树中的每个节点代表许多节点。而实际节点的类型为(node,param) 对于处理这类树的算法,param不会对其进行筛选。它们只是占位符。但是一些数据应该可以从普通参数或节点和参数的组合中提取,并且所有可能的参数都应该是可匹配的。所有这些类型的数据都是先验的,它们反映了树的语义 所以,param的实际类型、语义和内容取决于树的实现 C++
C++中使用嵌套类型DEFS对PARAMS模型进行建模,对于算法应该使用的所有类型的固定方法名称(这两个概念一起构成)和算法本身模板。 也就是说,如果我想将大树的每个节点关联为一个整数,我将提供一个函数
int data(const node&n,const param&p)
,其中param
可以作为嵌套的typedef使用,算法可以得到所有可用参数的列表,并使用感兴趣的节点和每个参数调用data
我有一些简单的数据类型,例如树数据,如下所示
data Tree = Node [Tree] | Leaf
现在我想打包:
- 混凝土树
- 某种类型
- 这种类型的一些值
- 在树节点和值上操作的一些函数
我来到了一个典型的家庭
class PackagedUp t where
type Value t
tree :: Tree t
values :: [Value t]
f :: Tree t -> Value t -> Int
Tree
现在变为treet t
,因为类型族希望其成员的类型依赖于类型类参数
此外,与类型族一样,还需要处理注入性
有了这个我可以
instance PackagedUp MyTree where
type Value MyTree = (Int,Int)
tree = Leaf
values = [(0,0),(1,1)]
f t v = fst v
现在如何编写这样的函数?也就是说,一个函数将以一棵树的根、所有值和所有树值的
[Int]
为根。首先,树类型的定义如下:
data Tree a = Node a [Tree a] | Leaf
上面的类型是多态的。就语义而言,它类似于我们在OO术语中所称的泛型类型(在C#或Java中,我们可能会编写
树模块,它提供了一个与您想要定义的非常相似的数据结构。您对树的定义不是您想要的,我非常确定您不需要走到类型族的地步来解决您的问题。然而,为了给出一个有用的答案,我们需要知道您想要的fFunctor
就是这样一个接口,因为fmap
可以处理树、列表和大量其他数据结构。但是,在您的情况下,您只有一个数据类型,因此不需要从中提取类型类。获取或返回树a
的函数的多态性就足够了例如,我在上面定义的getRoot
可以处理包含任何类型元素的树。我刚刚意识到,函数可以是数据的成员,因此我可以在不使用类的情况下拆分实现和调用!虽然它不在基中
,但树
似乎是be a.getRoot
将被称为extract
。事实上,定义的树
看起来非常类似于a。@MikhailCheshkov试图将Haskell当作一种OO语言来编写,这在绝大多数情况下只会导致头痛。耦合问题在Haskell中的表现方式与在OOP中不同,并且因此,解决方案也不同。如果你想自由地改变实现,大部分时候你需要做的就是将你的函数放在一个模块中,然后只导出你想在公共API中导出的函数。这就是augustss在提到模块时的意思。
getRoot :: Tree a -> Maybe a
getRoot Leaf = Nothing
getRoot (Node x _) = Just x
instance Functor Tree where
fmap f Leaf = Leaf
fmap f (Node x ts) = Node (f x) (fmap f ts)
fmap :: Functor f => (a -> b) -> f a -> f b
fmap :: (a -> b) -> Tree a -> Tree b
fmap :: (a -> b) -> [a] -> [b]