This problem came up when I was trying to zip through lists of different length and I didn't want them to be cut by the shortest one. It was in a context where the list had integers that I wanted to add or multiply. My problem is how to set up the type variables so that it can be more general.
zipWithPadding :: a -> (a -> a -> a) -> [a] -> [a] -> [a]
zipWithPadding n f = go n f
where
go n f [] a = [f n x | x <- a]
go n f a [] = [f n x | x <- a]
go n f (x:xs) (y:ys) = f x y : go n f xs ys
Currently, because the element to pad the lists with has to be speficied, I have to write them this way, but it begs the question of whether it needs to be custom made for each context, or simply repurposed with higher order functions.
Edit: I would like to thank Chris in the comments for the help. It made the example at the bottom possible by changing the above solution into this:
zipPadWith :: a -> b -> (a -> b -> c) -> [a] -> [b] -> [c]
zipPadWith n m f = go n m f
where
go n _ f [] a = [f n x | x <- a]
go _ m f a [] = [f x m | x <- a]
go n m f (x:xs) (y:ys) = f x y : go n m f xs ys
The example being:
transposeWith :: a -> [[a]] -> [[a]]
transposeWith n [] = []
transposeWith n (ms:mss) = zipPadWith n [] (:) ms (transposeWith n mss)
It transposes the list of lists without cutting content.