您可以先将zip 列表[1..] 与您的列表一起应用,然后应用replicate 和concat 结果:
rep xs = concatMap (uncurry replicate) $ zip [1..] xs
示例运行:
Prelude> let rep xs = concatMap (uncurry replicate) $ zip [1..] xs
Prelude> rep "abcd"
"abbcccdddd"
这个想法很简单,我们将每个元素与它应该重复的次数相关联。
zip 函数的类型为[a] -> [b] -> [(a, b)],因此它接受两个列表并返回一个配对列表,其中第一个元素来自第一个列表,第二个元素来自第二个列表。在我们的例子中,结果的类型为 [(Int, a)] 和 a,具体取决于参数。
replicate :: Int -> a -> [a] 函数接受一个表示长度的整数和一个元素x,并生成一个给定长度的列表[x, x, x, ..., x]。
uncurry 函数接受一个 a -> b -> c 类型的函数,即有两个参数,并将其转换为一个类型为 (a, b) -> c 的函数,即一个参数是一个元组。所以uncurry replicate 的类型为(Int, a) -> [a]。
现在类型匹配,您可以通过ziped 列表的map 函数获得[[a]],然后使用concat 连接结果。 concatMap 只是 concat . map 的简写。
您可以使用zipWith 函数,而不是使用zip,然后使用maping:
rep xs = concat $ zipWith replicate [1..] xs
请注意,您的解决方案似乎工作正常:
Prelude> let rep [] = []; rep (x:xs) = [ (x:xs)!! y | y <- [0..length xs], _<-[1..y+1]]
Prelude> rep [1,2,3]
[1,2,2,3,3,3]
Prelude> rep "abcd"
"abbcccdddd"
如果您有一个未产生正确结果的示例,请将其发布在您的问题中。
但是效率低下。处理列表时应避免使用!! 和length,而更喜欢map 和folds 之类的内容。
此外,我不相信上述函数可以为[Int] 产生正确的结果,但不能为String 产生正确的结果,原因很简单:该函数是多态的,因此通过参数化,元素的类型无关紧要列表包含的内容,仅与长度有关,结果将始终具有相同的形状(如果您看到该函数从不“查看”/“操作”元素,它只是移动它们;它做的事情完全相同独立于它们的特定类型。)