9

I am currently learning Applicatives in Haskell. If I am not wrong, there are two different Applicative instances for Lists, (List and ZipList - the second being defined as a newtype wrapping a List value). The ZipList applicative instances seems more intuitive for me.

It might be a dumb question, but is there a specific reason ZipList is not the default Applicative instance for Lists.

pure (+) <*> [1,2,3] <*> [4,5,6]
-- [5,6,7,6,7,8,7,8,9]

pure (+) <*> ZipList [1,2,3] <*> ZipList [4,5,6]
-- ZipList [5,7,9]

Is it because the distributive version of Applicative List also happens to have a Monad instance?

zeronone
  • 2,912
  • 25
  • 28
  • 5
    What happens when the lists are of varying lengths? Either you silently lose information (scary) or you have partial functions (even worse). I think making that behavior opt-in makes people more likely to consider the consequences. In contrast, the default Applicative and Monad instances are lossless and therefore less likely to silently cause problems, and are probably just more conceptually satisfying. Plus they generalize the idea of Maybe quite nicely (instead of 0 or 1 values you can encode any number of values, encoding a sort of nondeterminism or ambiguity). – Alexis King Jun 04 '16 at 07:18
  • 1
    I think the default one is more `elementary` in a sense similar to `free` objects in category theory. It preserves the most information and alternatives can be assigned to this default by forgetting some of the information. Here the `ZipList` forgets about some of the pairs of elements that the default considers. But I am really not too familiar with categories yet so don't quote me :) – jakubdaniel Jun 04 '16 at 07:58

1 Answers1

16

I suspect the honest answer here is "historical accident". The monad abstraction was popular before the applicative one was; since there is a natural list monad, that instance was defined. For backwards compatibility, it makes sense to keep the functor and applicative instances consistent moving forward.

That said, if we had to make the choice again today, I think I would support the current situation anyway: the nondeterminism monad is useful as a syntactically cheap backtracking search, and I've taken advantage of that frequently; arbitrary-arity zipping is (in my personal experience) a much less frequent need.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • 8
    I think it would be better to require newtype wrapping for both, so that intent is clealy expressed. Lists don't have intent. –  Jun 04 '16 at 10:53
  • 3
    There's also the fact that we want `Applicative` and `Monad` instances to agree; since `ZipList`s aren't `Monad`s, if we want lists to be `Monad`s, then they have to use the nondeterminism `Applicative` semantics as well. (This also prevents the newtype-both-of-them approach: we *have* to give them an `Applicative` instance to give them their only possible `Monad` instance!) – Antal Spector-Zabusky Jun 04 '16 at 20:35