列表中的元素对

pio*_*rek 6 haskell clojure

我想转换[1,2,3,4][[1 2] [2 3] [3 4]][(1 2) (2 3) (3 4)].在clojure我有(partition 2 1 [1,2,3,4]).我怎么能在haskell中做到这一点?我怀疑标准api中有这样的功能,但我找不到它.

ham*_*mar 19

对此的标准技巧是zip它自己的列表tail:

> let xs = [1,2,3,4] in zip xs (tail xs)
[(1,2),(2,3),(3,4)]
Run Code Online (Sandbox Code Playgroud)

要了解其工作原理,请在视觉上排列列表及其尾部.

      xs = 1 : 2 : 3 : 4 : []
 tail xs = 2 : 3 : 4 : []
Run Code Online (Sandbox Code Playgroud)

并注意到zip每列都有一个元组.

有两个更微妙的原因,为什么这总是正确的事情:

  • zip当任一列表用完元素时停止.这是有道理的,因为我们最终不能有一个"不完整的对",它也确保我们不会从单个元素列表中获得任何对.
  • xs为空时,可能会tail xs抛出异常.但是,因为zip 首先检查它的第一个参数,当它看到它是空列表时,永远不会评估第二个参数.

以上所有内容也适用于此zipWith,因此您可以在需要将函数成对应用于相邻元素时使用相同的方法.

对于像Clojure这样的通用解决方案partition,标准库中没有任何内容.但是,您可以尝试这样的事情:

partition' :: Int -> Int -> [a] -> [[a]]
partition' size offset
  | size <= 0   = error "partition': size must be positive"
  | offset <= 0 = error "partition': offset must be positive"
  | otherwise   = loop
  where
    loop :: [a] -> [[a]]
    loop xs = case splitAt size xs of
                -- If the second part is empty, we're at the end. But we might
                -- have gotten less than we asked for, hence the check.
                (ys, []) -> if length ys == size then [ys] else []
                (ys, _ ) -> ys : loop (drop offset xs)
Run Code Online (Sandbox Code Playgroud)