如何编写可重复遍历列表直到h为0的Haskell函数inc_until?
Haskell实现inc_until函数:循环遍历列表直到h减为0
问题分析
你当前的代码仅能遍历输入列表一次,当列表遍历完成但h仍大于0时会直接终止,无法满足循环遍历直到h变为0的需求。要解决这个问题,需要引入辅助函数保存原始列表,当当前遍历的列表为空时,重新从原始列表开始遍历。
解决方案
实现思路
- 使用辅助函数携带原始列表作为参数,确保在当前遍历的列表耗尽时,能重新从原始列表开始循环。
- 当
h减至0时,停止处理并返回结果。 - 遍历过程中,遇到偶数元素则加1并将
h减1,否则直接保留元素并继续遍历。
修正后的代码
inc_until :: Integer -> [Integer] -> [Integer] inc_until h xs = go h xs xs where -- 当h为0时,停止处理 go 0 _ _ = [] -- 当前列表遍历完,重新从原始列表开始 go h orig [] = go h orig orig -- 处理当前元素 go h orig (x:xs) | x `mod` 2 == 0 = (x + 1) : go (h - 1) orig xs | otherwise = x : go h orig xs
代码解释
- 主函数
inc_until调用辅助函数go,传入初始的h、当前遍历列表xs和原始列表xs。 - 辅助函数
go的第一个模式匹配处理h=0的终止条件,直接返回空列表。 - 第二个模式匹配处理当前列表为空的情况,递归调用
go并传入原始列表,实现循环遍历。 - 第三个模式匹配处理单个元素:如果是偶数则加1并减少
h,否则直接保留元素,继续遍历剩余列表。
针对测试用例的说明
你的测试用例inc_until 4 [1,2,3,4,5]期望返回[1,4,3,6,5],这意味着需求是对原始列表中的偶数元素累计加1次数(而非遍历修改后的列表)。如果是这种需求,需要调整实现逻辑:统计每个原始偶数元素被选中的次数,最终返回原始元素加上对应次数的结果。实现代码如下:
import Data.List (elemIndex) import Data.Array (Array, listArray, (!), (//)) inc_until :: Integer -> [Integer] -> [Integer] inc_until h xs = map (\x -> x + countArr ! idx) xs where len = length xs -- 生成循环的原始偶数元素索引序列 evenIndices = cycle [i | (i, x) <- zip [0..] xs, x `mod` 2 == 0] -- 初始化计数数组,所有元素初始为0 initArr = listArray (0, len-1) (replicate len 0) :: Array Int Int -- 统计前h次操作中每个索引被选中的次数 countArr = foldr (\i arr -> arr // [(i, arr ! i + 1)]) initArr (take (fromIntegral h) evenIndices) -- 获取元素在原列表中的索引 idx x = case elemIndex x xs of Just i -> i; _ -> 0
注意:此版本仅适用于有限列表,因为需要预先统计元素索引;如果要同时支持无限列表,建议采用第一种遍历序列的实现方式。
内容的提问来源于stack exchange,提问作者Bence Tolvaj
相关产品推荐
相关产品推荐

