Haskell二叉树递归
我是haskell的初学者,需要根据列表(路径)中指定的方向在树中显示值。我在下面列出了数据结构,我想了解为什么我实现的递归特性是错误的Haskell二叉树递归,haskell,recursion,Haskell,Recursion,我是haskell的初学者,需要根据列表(路径)中指定的方向在树中显示值。我在下面列出了数据结构,我想了解为什么我实现的递归特性是错误的 import Data.List data Step = L | R deriving(Eq,Show) type Path = [Step] data Tree a = Node a (Tree a) (Tree a) | End deriving (Eq,Show) leaf :: a
import Data.List
data Step = L | R
deriving(Eq,Show)
type Path = [Step]
data Tree a = Node a (Tree a) (Tree a)
| End
deriving (Eq,Show)
leaf :: a -> Tree a
leaf x = Node x End End
ex :: Tree Int
ex = Node 4 (Node 3 (leaf 2) End)
(Node 7 (Node 5 End (leaf 6))
(leaf 8))
valueAt :: Path -> Tree a -> Maybe a
valueAt (p:ps) (Node a l r)
| p == L = valueAt ps l
| p == R = valueAt ps r
| ps == [] = Just
| otherwise = Nothing
//当我执行这个函数时,它在valueAt表示非穷举函数。所以我猜我的递归思想是实现错误的。有人能解释一下原因吗。您没有在[]someTree处理这个案例。行
valueAt(p:ps)…
仅匹配以p
开始并继续以ps
继续的非空列表ps
可能为空,但p:ps
从不为空
如果使用标志-Wall
进行编译,GHC应在编译时发出警告。我强烈建议这样做
作为一种风格建议,避免使用诸如p==…
之类的防护,因为它们不执行任何模式匹配。试着像这样做
valueAt :: Path -> Tree a -> Maybe a
valueAt [] (Node a _ _) = Just a -- note the "a" !
valueAt (L:ps) (Node _ l _) = valueAt ps l
valueAt (R:ps) (Node _ _ r) = valueAt ps r
valueAt _ End = Nothing -- in all the other cases
valueAt
的模式匹配不包括[]
,因为(p:ps)
将在空列表中失败。但是,它没有必要这样做。按照编写顺序对保护进行评估,这意味着在您的ps=[]
案例之前对p==L
和p==R
保护进行评估。换句话说,您已经将您的边缘案例放在递归案例之后,导致了无效的模式匹配。这段代码应该可以解决这个问题
valueAt (p:ps) (Node a l r)
| ps == [] = Just
| p == L = valueAt ps l
| p == R = valueAt ps r
| otherwise = Nothing
但是,您的代码还有另一个问题。该函数具有类型描述valueAt::Path->Tree a->Maybe a
,但在您的边缘情况下(ps=[]
),只是具有类型a->Maybe a
<代码>仅
应用于太少的参数。试试这个
| ps == [] = Just a
既然您的错误已经修复,我还建议您从警卫和==
转移到模式匹配。它将更简单、更快、更不容易出错
valueAt :: Path -> Tree a -> Maybe a
valueAt [] (Node a _ _) = Just a
valueAt (L:ps) (Node _ l _) = valueAt ps l
valueAt (R:ps) (Node _ _ r) = valueAt ps r
valueAt _ _ = Nothing
正确缩进代码<代码>值按原样,继续上一行。。。8) )
!不要在这里使用==
。它有它的用途,但它根本不属于这段代码。在这里使用模式匹配而不是警卫。嘿,非常感谢,这帮了大忙,是的,警卫让它看起来更复杂。谢谢你花时间在这上面。