我有这个问题要做:
“定义一个函数findpath:: BTree a -> a -> Path
(其中Btree
a在前面的问题中被定义),给定二叉树t
和值x
,返回一个从t
的根到一个值为x
的叶子(如果有的话),另一个值为Nothing
。程序的运行时间应该是线性的树。“
到目前为止,我有:
data Maybe a = Nothing | Just a
data BTree a = Leaf a | Fork (BTree a) (BTree a)
type Path = Maybe [Dir]
data Dir = Left | Right
findpath :: Eq a => BTree a -> a -> Path
findpath (Leaf y) x = if y==x then ??? else Nothing
findpath (Fork l r) x = nodepath (findpath l x) (findpath r x) where
nodepath :: Path -> Path -> Path
nodepath Nothing Nothing = Nothing
nodepath Nothing pathr = Just [R]
nodepath pathl Nothing = Just [L]
我仍然无法在(Leaf y)
案例
答案 0 :(得分:13)
您的语言,关于您认为该计划应该做什么,向我建议您需要帮助才能摆脱强制性思维的陷阱。让我尝试提供一些帮助,基于对 的内容的思考,而不是做什么。
对于findpath (Leaf y) x
,您正朝着正确的方向前进。您只需要将if
改为小写i
,并考虑Path
到Leaf
的正确位置。
现在,让我们考虑另一种可能性。你知道的不仅仅是t
。你知道你真的想弄明白什么
findpath (Node l r) x
(确实是=
),因为这是BTree
的另一种可能性。考虑通过询问“这是BTree
一个(Leaf y)
还是(Node l r)
来解决问题?”作为程序设计的一个概念步骤。现在,为了弄清楚上面的左边是什么,你有权获得一些递归计算的信息,即什么
findpath l x
和
findpath r x
是。如果您知道Path
和l
的{{1}}信息,您能说出整个r
的{{1}}是什么吗?让我在Haskell中写一下这个问题:
Path
我通过引入辅助函数 Node l r
表达了我的问题,该函数将递归计算的信息作为参数。现在,您可以尝试分别通过左右子树的这两个路径上的模式匹配来实现findpath :: Eq a => BTree a -> a -> Path
findpath (Leaf y) x = if y==x then ??? else Nothing
findpath (Node l r) x = nodepath (findpath l x) (findpath r x) where
nodepath :: Path -> Path -> Path
nodepath ???
。如果您知道它们是nodepath
还是nodepath
,那么您应该能够说明整个节点的路径必须是什么。
第一课,有用的想法是这样的形式:“如果这就像这样,那么那必定是某某。”存在,不做。
第二课,对数据类型进行编程的基本方法是:拆分为构造函数案例((Just p)
与Nothing
,Leaf
与Node
);通过递归调用从任何子结构中收集有用的信息;说出整个结构的价值必须是什么。
如果您遵循我的建议并找出Just
应该是什么,您可能会发现它很简单,不值得单独命名。在这种情况下,只需将Nothing
调用替换为其含义,并删除nodepath
- 子句。但最好先介绍nodepath
,因为它表达了解决问题的有用概念步骤。