我试图弄清楚如何创建一个递归函数,它将找到列表中最大的元素并删除它然后返回列表。这是我到目前为止,但问题是,每次我运行它时,它返回列表,没有任何分配给x的值。
deleteMax :: (Ord a) => [a] -> [a]
deleteMax [] = []
deleteMax [x] = []
deleteMax (x:y:xs)
|x == y = y: deleteMax xs
|x >= y = y: deleteMax xs
|x < y = x: deleteMax xs
答案 0 :(得分:0)
这不是您的答案
所以你是初学者,因此想要简单的解决方案&#34;如何找到列表中最大的元素&#34;然后是&#34;如何删除列表中的(最大的)一个(&)34个。这不是答案,但是我避免了长时间的评论,同时也给了你一些在3个月内回来的东西。
懒惰的方式
一个解决方案,@ n.m。而我在评论中正在争吵,就是打结(Googleable术语)。在此方法中,您只需要在列表上进行一次逻辑传递。在这种情况下,隐藏构造结果列表的传递基本上是一种技巧。
这个想法是,在您通过列表时,您执行以下两项任务:1。计算最大元素和2.与最大元素比较并构造列表。这里没有任何东西需要monad,但它最容易被视为状态monad的一部分:
deleteMaxState :: (Ord a) => [a] -> [a]
deleteMaxState [] = []
首先我们处理基本案例,以便我们有一个候选人“最大”&#39; (x
)用于我们的递归操作。
deleteMaxState xs@(fstElem:_) =
let (r,(m,_)) = runState (go xs) (fstElem, notMax m)
notMax mx v = if (mx > v) then (v:) else id
go [] = return []
go (x:xs) =
do (curr,f) <- get
when (x > curr) (put (x,f))
f x <$> go xs
in r
在循环中跟踪两个值,第一个curr
是我们遍历列表时此点的最大观察值。第二个值f
是技巧 - 它是(包括一个函数)在遍历完成后提供给计算的最大值。
魔法就在这里:
(r,(m,_)) = runState (go xs) (fstElem, m)
结果状态(m,_)
的左侧元素是我们的运行最大值。遍历结束后,我们使用该值 - 它成为正确的元素(fstElem, m)
,因此代表整个列表的最大值。
我们可以使用f
来创建填充列表部分的thunk,或者只是将我们的列表内联构造为一堆未经评估的cons
计算。
使这个更简单,我们可以删除高阶函数f
并且只有一个数字(未经测试):
deleteMaxState xs@(fstElem:_) =
let (r,(m,_)) = runState (go xs) (fstElem, m)
go [] = return []
go (x:xs) =
do (curr,theMax) <- get
when (x > curr) (put (x,theMax))
((if x >= theMax then Nothing else Just x) :) <$> go xs
in catMaybes r
现在我们可以非常明确地看到第二次传递不仅仅是一个未经评估的一组&#34;一些涉及max的计算,结果是#34;但作为catMaybes
的实际传递。
结的结合允许程序员编写一个逻辑遍历。这可能很好,因为它只需要一个模式匹配和列表元素的每个构造函数的递归调用,但代价是推理评估顺序。