5

I'm writing a function pad that takes a list and pads it until it is a certain size. I tried 2 implementations:

pad :: Monoid a => Int -> [a] -> [a]
pad len list = replicate (len - length list) mempty ++ list

and

pad :: Int -> a ->  [a] -> [a]
pad len value list = replicate (len - length list) value ++ list

The first one seems to be a logical usage of Monoid but calling it with lists of integers (or anything that is a Monoid in multiple ways) is a pain:

(fmap getSum) <$> pad 8 <$> (fmap Sum) <$> [1,2,3]

I don't really mind the extra typing, but it doesn't even seem to convey the meaning very well. How would you implement this function?

Drew
  • 12,578
  • 11
  • 58
  • 98
  • 1
    I would use `pad :: Int -> a -> [a] -> [a]`. Sometimes, one wants to pad with a different value. – Daniel Fischer May 29 '13 at 22:15
  • 4
    Exercise for the curious. Consider `data Paddy a = [a] :...: a` and equip `Paddy` with a zipping `Applicative` structure which pairs up the values left of `:...:` but deals with length mismatch by padding the shorter list with the value given after the `:...:`. – pigworker May 29 '13 at 22:28

1 Answers1

11

I'd probably use your second example, to be honest. Adding a Monoid constraint just to use mempty as a "default value" is overkill. It also sends the wrong message to users of this function, who may be confused about what you need mappend for when you really don't. They would also have to make a newtype and a Monoid instance if they wanted to pad with a different value.

Instead, consider changing the order of the arguments so that the value comes first. Then you can just apply it partially whenever you need to pad a lot of lists with the same value. You can also recover the first version with pad mempty if you need it.

hammar
  • 138,522
  • 17
  • 304
  • 385