Using list elements and indices together

后端 未结 2 1545
广开言路
广开言路 2020-12-30 05:19

I\'ve always found it awkward to have a function or expression that requires use of the values, as well as indices, of a list (or array, applies just the same) in Haskell.

2条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-30 05:35

    Borrowing enumerate is fine and encouraged. However, it can be made a bit lazier by refusing to calculate the length of its argument:

    enumerate = zip [0..]
    

    (In fact, it's common to just use zip [0..] without naming it enumerate.) It's not clear to me why you think your second example should be costlier in either time or space. Remember: indexing is O(n), where n is the index. Your complaint about the unwieldiness of fst and snd is justified, and can be remedied with pattern-matching:

    validQueens' xs = and [abs (y - x) /= j - i | (i, x) <- l, (j, y) <- l, i < j]
        where l = zip [0..] xs
    

    Now, you might be a bit concerned about the efficiency of this double loop, since the clause (j, y) <- l is going to be running down the entire spine of l, when really we just want it to start where we left off with (i, x) <- l. So, let's write a function that implements that idea:

    pairs :: [a] -> [(a, a)]
    pairs xs = [(x, y) | x:ys <- tails xs, y <- ys]
    

    Having made this function, your function is not too hard to adapt. Pulling out the predicate into its own function, we can use all instead of and:

    validSingleQueen ((i, x), (j, y)) = abs (y - x) /= j - i
    validQueens' xs = all validSingleQueen (pairs (zip [0..] xs))
    

    Or, if you prefer point-free notation:

    validQueens' = all validSingleQueen . pairs . zip [0..]
    

提交回复
热议问题