我不确定我的命名法在这里是否正确,但是我想知道Haskell中是否有一个贪婪的zip函数。这意味着如果我有

a = [1, 2, 3]
b = [4, 5]
zip' a b
#=> [(Just 1, Just 4),(Just 2, Just 5),(Just 3, Nothing)]

...其中zip'是贪婪的zip函数,它将返回长列表长度的元组列表,而长列表具有元素,但短列表中没有Nothing放在相应的元组位置。我不是在问怎么写,而是想知道它是否以内置形式存在。

这是我的实现(可能不是很好)
zip' :: [a] -> [b] -> [(Maybe a, Maybe b)]
zip' (a:xs) [] = (Just a, Nothing) : zip' xs []
zip' [] (b:ys) = (Nothing, Just b) : zip' [] ys
zip' [] _ = []
zip' (a:xs) (b:ys) = (Just a, Just b) : zip' xs ys

最佳答案

贪婪的zip可以通过非排他的析取类型(而不是Either,这是排他的析取)来整洁地表示。有两个流行的软件包可以提供这一点。一种是极简的,无依赖的data-or:

GHCi> import Data.Or
GHCi> :t zipOr
zipOr :: [a] -> [b] -> [Or a b]
GHCi> zipOr [1, 2, 3] [4, 5]
[Both 1 4,Both 2 5,Fst 3]

另一个是these,它带有许多风铃:
GHCi> import Data.These
GHCi> import Data.Align
GHCi> :t align
align :: Align f => f a -> f b -> f (These a b)
GHCi> align [1, 2, 3] [4, 5]
[These 1 4,These 2 5,This 3]

我相信Or a bThese a b可以比(Maybe a, Maybe b)更好地表达您的意图(后者类型包括(Nothing, Nothing),贪婪的zip永远不会产生)。不过,您仍然可以使用zip'中的zipOrWith来表达自己的Data.Or ...
import Data.Or

zip' :: [a] -> [b] -> [(Maybe a, Maybe b)]
zip' = zipOrWith $ \xy -> case xy of
    Both x y -> (Just x, Just y)
    Fst x -> (Just x, Nothing)
    Snd y -> (Nothing, Just y)

...或alignWith中的Data.Align:
import Data.These
import Data.Align

zip' :: Align f => f a -> f b -> f (Maybe a, Maybe b)
zip' = alignWith $ \xy -> case xy of
    These x y -> (Just x, Just y)
    This x -> (Just x, Nothing)
    That y -> (Nothing, Just y)

实际上,Data.Align padZip 的名称提供了您的功能。

关于haskell - Haskell是否有贪婪的zip(一个保留所有元素的 zipper )?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41336345/

10-13 03:10