Если вы считаете (неявные) индексы каждого элемента списка как свои ключи, то zipWith
является своего рода реляционным внутренним соединением. Он обрабатывает только ключи, для которых оба входа имеют значения:Функция канонического внешнего соединения zip
zipWith (+) [1..5] [10..20] == zipWith (+) [1..11] [10..14] == [11,13,15,17,19]
Есть ли каноническая соответствующая функция, соответствующая внешнему соединению? Что-то вроде:
outerZipWith :: (a -> b -> c) -> a -> b -> [a] -> [b] -> [c]
outerZipWith _ _ _ [] [] = []
outerZipWith f a' b' [] (b:bs) = f a' b : outerZipWith f a' b' [] bs
outerZipWith f a' b' (a:as) [] = f a b' : outerZipWith f a' b' as []
outerZipWith f a' b' (a:as) (b:bs) = f a b : outerZipWith f a' b' as bs
или, может быть,
outerZipWith' :: (a -> b -> c) -> Maybe a -> Maybe b -> [a] -> [b] -> [c]
outerZipWith' _ _ _ [] [] = []
outerZipWith' _ Nothing _ [] _ = []
outerZipWith' _ _ Nothing _ [] = []
outerZipWith' f a' b' [] (b:bs) = f (fromJust a') b : outerZipWith f a' b' [] bs
outerZipWith' f a' b' (a:as) [] = f a (fromJust b') : outerZipWith f a' b' as []
outerZipWith' f a' b' (a:as) (b:bs) = f a b : outerZipWith f a' b' as bs
Так что я могу сделать
outerZipWith (+) 0 0 [1..5] [10..20] == [11,13,15,17,19,15,16,17,18,19,20]
outerZipWith (+) 0 0 [1..11] [10..14] == [11,13,15,17,19,6,7,8,9,10,11]
Я считаю себя нуждаясь это время от времени, и я предпочел бы использовать общий идиома сделайте мой код более доступным для записи (и проще в обслуживании), вместо того, чтобы реализовать outerZipWith
или сделать if length as < length bs then zipWith f (as ++ repeat a) bs else zipWith f as (bs ++ repeat b)
.
Не будет 'outerZip :: a -> b -> [a] -> [b] -> [(a, b)]'? – pat
Больше похоже на 'outerZip :: (a -> c) -> (b -> d) -> c -> d -> [a] -> [b] -> [(c, d)]' – Apocalisp
Включая Тип или тип (например, ваш «Эти») может быть необходимым первым шагом. По крайней мере, это хорошее место для начала. – rampion