[英]Haskell delete largest number from a list
我想弄清楚如何创建一个递归函数,该函数将找到列表中最大的元素并删除它然后返回列表。 这是我到目前为止所拥有的,但问题是每次我运行它时,它都会返回没有分配给 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
这不是你的答案
因此,您是初学者,因此想要“如何找到列表中最大的元素”的简单解决方案,然后是“如何删除列表中的(一个)最大元素”。 这不是那个答案,而是我避免了冗长的评论,同时也给了你一些可以在 3 个月内回来的东西。
懒惰的方式
@nm 和我在评论中争论的一个解决方案是打结(Googleable 术语)。 在这种方法中,您只需要对列表进行一次逻辑传递。 在这种情况下,隐藏构建结果列表的过程基本上是一个技巧。
这个想法是,在你传递列表的过程中,你完成了 1. 计算最大元素和 2. 与最大元素比较并构建列表的两个任务。 这里没有任何需要 monad 的东西,但最容易将其视为状态 monad 的一部分:
deleteMaxState :: (Ord a) => [a] -> [a]
deleteMaxState [] = []
首先我们处理基本情况,所以我们有一个候选的“最大值”( 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
现在我们可以非常明确地看到第二次传递不仅仅是一组未评估的“一些涉及最大值的计算,根据结果”,而是作为通过catMaybes
的实际传递。
打结允许程序员编写一个逻辑遍历。 这可能很好,因为它只需要一个模式匹配和每个列表元素构造函数的递归调用,但代价是推理评估顺序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.