删除Haskell中每次出现的Nil

时间:2014-11-30 14:20:16

标签: haskell tree comparison

在大学时,我们收到了编写函数的任务

> deleteNil :: Tree a -> Tree a

删除类型

树中每次出现的Nil

> data Tree a = Nil | Leaf a | Br ( Tree a ) ( Tree a )

如果Tree只包含Nil,则返回值也应为Nil。 唯一的限制是,树的类型签名和函数deleteNil的签名都不允许被编辑,例如,我不被允许追加 deriving Eq, Show 到树a的类型签名。

我第一次尝试解决这个问题如下:

> deleteNil :: Tree a -> Tree a
> deleteNil Nil = Nil
> deleteNil (Br l r)
>        | deleteNil l == Nil && deleteNil r == Nil = Nil
>        | deleteNil l == Nil && deleteNil r /= Nil = r
>        | deleteNil l /= Nil && deleteNil r == Nil = l
>        | deleteNil l /= Nil && deleteNil r /= Nil = Br l r

但显然因为我不允许派生Eq这个版本给我编译错误

No instance for (Eq (Tree a)) arising from a use of '=='

我不想在这里要求找到这个问题的完整解决方案,但有人为我提供了一种新的方法,我应该如何尝试解决这个问题而不必比较树的部分?

2 个答案:

答案 0 :(得分:2)

嗯,你几乎做对了,你错过的是你可以在lr上进行模式匹配:

deleteNil :: Tree a -> Tree a
deleteNil Nil = Nil
deleteNil (Br Nil Nil) = Nil
deleteNil (Br   l Nil) = (deleteNil l)
deleteNil (Br Nil   r) = (deleteNil r)
deleteNil (Br   l   r) = case (deleteNil l, deleteNil r) of
    (Nil, Nil) -> Nil
    (nl, Nil) -> nl
    (Nil, nr) -> nr
    (nl, nr) -> Br nl nr

请注意功能中的Leaf选项。

答案 1 :(得分:1)

您可以使用模式匹配:

deleteNil :: Tree a -> Tree a
deleteNil (Br l r) = case (deleteNil l, deleteNil r) of
    (Nil, dr ) -> dr
    (dl , Nil) -> dl
    (dl , dr ) -> Br dl dr
deleteNil  t       = t

所以你不需要四个案例,因为这两个

| deleteNil l == Nil && deleteNil r == Nil = Nil
| deleteNil l == Nil && deleteNil r /= Nil = r

实际上就是这个:

| deleteNil l == Nil = deleteNil r

因为它应该是

| deleteNil l == Nil && deleteNil r /= Nil = deleteNil r

因为你想要返回一个不包含Nil s。

的树

此外,您可以为Eq类型类提供实例:

instance Eq (Tree a) where
    Nil      == Nil      = True
    Br l1 r1 == Br l2 r2 = l1 == l2 && r1 == r2
    _        == _        = False