我不确定我的命名法在这里是否正确,但是我想知道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 b
和These 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/