哈斯克尔.跟踪索引以生成新列表

J. *_*bal 6 haskell functional-programming list-comprehension list

我决定学习Haskell并学习以更实用的方式思考,所以我试图解决非常简单的练习,试图在这个范例中使用一个好的方法.

我想在Haskell中实现这个简单的练习:

Input: [2, 4, 1, 1, 2]
Output: [True, True, False, False, False, False, True, False, True, True]
Run Code Online (Sandbox Code Playgroud)

所以,在元素Input列表将下降到是FalseOutput列表中,奇数元素将是True; 每个重复的次数与Input列表中的值相同.

遍历Input列表,如果  ᵗʰ项目是在一对位置上,附加到输出True Output; 如果  ᵗʰ产品在奇数位置,追加False 倍到Output列表中.

这似乎是一个非常简单的问题,而且确实如此.但对我来说,没有任何函数式编程背景,我不知道如何在Haskell中表达它.

我试图通过在列表理解中使用λ函数来跟踪当前索引.

    row :: [Integer] -> [Bool]
    row xs = [ (last $ zipWith (\i x -> x) [1..] [0..i]) `mod` 2 == 0
                | j <- xs, i <- [0..j-1] ]
Run Code Online (Sandbox Code Playgroud)

但是我不了解它的行为,所以我最终选择使用它findIndices 作为一个快速的选择:

    row :: [Integer] -> [Bool]
    row xs = [ (head $ findIndices (==j) (xs)) `mod` 2 == 0
                | j <- xs, i <- [0..j-1] ]
Run Code Online (Sandbox Code Playgroud)

使用这最后一种方法似乎没问题:

    > let xs = [ 1, 4, 3, 2 ]
    > print $ row xs
    [True,False,False,False,False,True,True,True,False,False]
Run Code Online (Sandbox Code Playgroud)

但问题没有解决,因为这些项目不一定是唯一的:

    > let xs = [ 2, 2, 4, 3]
    > print $ row xs
    [True,True,True,True,True,True,True,True,False,False,False]
Run Code Online (Sandbox Code Playgroud)

因为head findIndices只给出了第一次出现.(虽然我认为,如果有效,那不是解决这个问题的有效方法.)

如何以Haskellian方式实现我正在寻找的结果?

Dan*_*her 11

您希望将输入列表中的每个元素转换Bool为与元素所示的数量相等的序列,如果输入列表中的数字索引是偶数,并且索引是奇数,则需要Boolbe .TrueFalse

为此,您不需要索引,最好避免使用 - 这样可以提供更简单且通常更高效的代码.关键是该值交替出现,它具有周期性模式.为了构建这样的周期性模式,Prelude提供了有用的

cycle :: [a] -> [a]

Prelude> take 10 $ cycle [1,2,3]
[1,2,3,1,2,3,1,2,3,1]
Prelude> take 10 $ cycle [True,False]
[True,False,True,False,True,False,True,False,True,False]
Run Code Online (Sandbox Code Playgroud)

整洁,这正是我们所需要的.

现在,我们可以将输入列表的每个元素与相应的配对Bool:

[  2,    2,   4,   3]
[True,False,True,False,...
Run Code Online (Sandbox Code Playgroud)

我们可以zip用来生成对,[(2,True), (2,False), ...]然后使用一个函数将该对转换为适当的Bools 序列.

但是这种模式非常普遍,我们有一个特殊的高阶函数,zipWith.

因此,如果列表元素的类型是Int,我们可以写

row :: [Int] -> [Bool]
row xs = concat $ zipWith replicate xs (cycle [True,False])
Run Code Online (Sandbox Code Playgroud)

对于类型Integer,我们不能用replicate,但我们可以用genericReplicateData.List.