在Haskell中定义对bush数据类型的相等操作

在Haskell中定义对bush数据类型的相等操作,haskell,types,nested,Haskell,Types,Nested,我已经定义了一个嵌套的数据类型: data Bush a = BEmpty | BCons a (Bush(Bush a)) 现在我试着在灌木丛上定义一个相等的函数: eqB :: Eq a => Bush a -> Bush a -> Bool eqB BEmpty BEmpty = True eqB BEmpty _ = False eqB _ BEmpty = False eqB (BCons x bbush1) (BCons y bbush2) = x == y --

我已经定义了一个嵌套的数据类型:

data Bush a = BEmpty | BCons a (Bush(Bush a))
现在我试着在灌木丛上定义一个相等的函数:

eqB :: Eq a => Bush a -> Bush a -> Bool
eqB BEmpty BEmpty = True
eqB BEmpty _ = False
eqB _ BEmpty = False
eqB (BCons x bbush1) (BCons y bbush2) = x == y -- && ....
问题在于递归调用
Bush(Bush)
我可以在
Bush(Bush)
上定义一个函数eqB',但是我必须在
Bush(Bush)(Bush))
上处理eq,等等


有办法解决这个问题吗?

例如,Bush Int中所有Int发生的总和

sum:: Bush Int -> Int
sum BEmpty = 0
sum (BCons i BEmpty) = i
sum (BCons i bbush) = i + sum' bbush 
我可以编写一个处理bbush的函数sum:

sum':: Bush (Bush Int) -> Int
sum' BEmpty = 0
sum' (BCons bush bbbush) = sum bush -- + sum'' bbbush
没有尽头

Bush
是一种“非规则”或“非统一”数据类型,这意味着在递归情况下,它不使用与给定类型参数相同的类型参数。这些问题有时很难推理,但在这种情况下,答案比你想象的要简单:

data Bush a = BEmpty | BCons a (Bush (Bush a))

instance Eq a => Eq (Bush a) where
    BEmpty == BEmpty = True
    BCons x xs == BCons y ys = x == y && xs == ys
    _ == _ = False
就这样<代码>(==)可以递归地调用自己,我们就完成了

但是,等等,我们在这里耍了一点小把戏:我们使用了
Eq
和类型类机制,这为我们做了艰苦的工作

如果我们根本没有类型类,我们怎么做呢?如果我们没有类型类,那么首先就不能使用
eqa=>
约束。相反,我们可以传递一个显式比较函数
::a->a->Bool
。考虑到这一点,我们可以编写非常类似的代码:

eqBush :: (a -> a -> Bool) -> Bush a -> Bush a -> Bool
eqBush _ BEmpty BEmpty = True
eqBush eqA (BCons x xs) (BCons y ys) = eqA x y && eqBush (eqBush eqA) xs ys
eqBush _ _ _ = False
在每个递归调用中,我们传递的不是我们得到的相同的比较函数——我们传递的是比较函数来比较
Bush a
s,而不是
a
s!除了更显式之外,这实际上与类型类发生的情况相同。注意我们递归调用的结构与数据类型定义的结构是如何相同的——我们有
Bush(Bush a)
,因此我们使用
eqBush(eqBush eqA)
进行递归

这种类型上的任何其他递归定义也会发生同样的情况。这里有一个有用的(这只是
fmap
对于
Bush
,真的):

这样,编写类似于
sumBush
的函数就很容易了:

sumBush :: Bush Int -> Int
sumBush BEmpty = 0
sumBush (BCons x xs) = x + sumBush (mapBush sumBush xs)
之所以调用这种递归,是因为多态函数调用自己的类型与调用它的类型不同。多态递归可能是一个棘手的问题——事实上,它的类型推断是不可判定的(一般来说),因此您必须编写自己的类型签名(一般来说)——但经过一点实践,它看起来会自然得多。试着在
Bush
上编写一些其他函数来了解它

下面是一些其他非常规数据类型,可以尝试为其编写一些代码:

  • 数据树a=叶a |分支(树(a,a))
    完美二叉树

  • data
    ab=doneb | morea(funlista(a->b))
    --一个
    a
    s的列表,以及一个函数,该函数精确地获取那么多
    a
    并返回一个
    b
    (这与此相关)


这就是解决方案。谢谢!
sumBush :: Bush Int -> Int
sumBush BEmpty = 0
sumBush (BCons x xs) = x + sumBush (mapBush sumBush xs)