我在编写带有谓词和整数列表的函数时遇到问题,然后消除了满足列表中谓词的最后一个整数。我能够使用下面的函数取出列表中第一次出现的谓词:
fun :: (Int -> Bool) -> [Int] -> [Int]
fun check (s:ss)
|check s = ss
|otherwise = s : fun check ss
我需要帮助的是如何修改此函数以取出最后一次出现的整数,而不是第一次出现。例如,fun (<2) [3,4,1,5,0,-3,9]
将返回[3,4,1,5,0,9]
。
答案 0 :(得分:4)
(由于某些缩进问题,我无法使用where
)
removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p xs =
let
go c [] = tail (c [])
go c (x:xs)
| p x = c (go (x:) xs)
| otherwise = go (c . (x:)) xs
in case break p xs of
(ok, []) -> ok
(ok, x:xs) -> ok ++ go (x:) xs
go
收集谓词在差异列表中不存在的元素,并在找到满足谓词元素的新元素后将此列表预先添加到结果中。 break p xs
上的模式匹配确保差异列表始终以满足谓词的元素开头,如果它是最后一个,我们可以删除它。
使用无限列表:
main = do
print $ removeLast (< 2) [3,4,1,5,0,-3,9] -- [3,4,1,5,0,9]
print $ removeLast (== 2) [1,3] -- [1,3]
print $ take 10 $ removeLast (< 2) (cycle [1,3]) -- [1,3,1,3,1,3,1,3,1,3]
这是一个混淆版本:
removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p xs = case break p xs of
(ok, []) -> ok
(ok, x:xs) -> ok ++ foldr step (tail . ($[])) xs (x:) where
step x r c = if p x then c (r (x:)) else r (c . (x:))
答案 1 :(得分:3)
如果你想玩得开心,试试这个版本。
removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p = fst . foldr go ([], False) where
go x ~(r, more)
| p x = (if more then x : r else r, True)
| otherwise = (x : r, more)
这似乎几乎和它一样懒惰,而且很快就达到了目的。它可以通过一些努力更懒惰地生成列表 spine ,但它最大限度地生成列表元素。
经过一番思考,我意识到在这种情况下,懒惰的不同方面之间存在一些紧张关系。考虑removeLast p (x : xs)
我们可以尝试两种方法来确定是否生成[]
或(:)
构造函数。
我们可以查看xs
;如果xs
不是[]
,那么我们就可以生成(:)
。
我们可以查看p x
。如果p x
为False
,那么我们就可以生成(:)
。
这是唯一的方法,它们的严格性无法比较。唯一的&#34;最大的懒惰&#34;方法是使用并行性来尝试两种方式,这不是最实用的方法。
答案 2 :(得分:0)
这个怎么样:
fun :: (Num a) => (a -> Bool) -> [a] -> [a]
fun check (s:ss)
|check s = ss
|otherwise = s : fun check ss
然后,像这样应用fun
函数:
reverse $ fun (\ x -> x `mod` 3 == 0) (reverse [1..10])
HTH