为何Scalaz的Apply[List].apply5性能如此低下?
Apply[List].apply5 is Extremely Slow for Zipping Lists Great question! Let's break down exactly why Apply[List].apply5 is performing so poorly compared to your step-by-step Zip approach, even when all your input lists are the same length.
The Core Difference: Apply[List] vs Zip[List]
The key issue boils down to completely different semantics between these two type classes for List:
Apply[List]is for Cartesian Products, Not Zipping
Scalaz'sApply[List]instance is built on top of theApplicative[List]implementation, which treats lists as non-deterministic values. When you callapply5, it generates every possible combination of elements from the input lists—this is a Cartesian product.For example, if each of your 5 lists has 10 elements,
apply5will produce10 * 10 * 10 * 10 * 10 = 100,000elements. If your lists are even a bit longer (say 100 elements), that jumps to 10 billion elements—no wonder your test case never finishes!Your code using
Apply[List].apply5isn't actually zipping (pairing elements by position) at all—it's generating every possible tuple combination across all lists.Zip[List]is Designed for Position-Based Pairing
TheZiptype class, on the other hand, exists specifically to do what you expect: pair elements from lists at the same position. Each call toZip[List].ziptakes two lists and returns a list of tuples where each tuple contains elements from the same index in the input lists. The result length matches the shortest input list (or all lists, in your case since they're the same length).Your step-by-step approach with
lzip2tolzip5builds up the 5-tuple by repeatedly zipping pairs, which keeps the result length equal to your input lists—so even for large lists, it runs efficiently.
Example to Illustrate
Let's use small lists to see the difference:
val l1 = List(1, 2) val l2 = List(3, 4) val l3 = List(5, 6) val l4 = List(7, 8) val l5 = List(9, 10) // Using Apply[List].apply5: produces 32 elements (2^5) Apply[List].apply5(l1,l2,l3,l4,l5)((a,b,c,d,e) => (a,(b,(c,(d,e))))) // Using your Zip-based zip5: produces 2 elements zip5(l1,l2,l3,l4,l5)
Takeaway
If you need to zip lists by position (the standard zip behavior), always use the Zip type class (either via step-by-step zips or Scalaz's zipN utilities if available). Apply[List]'s applyN methods are meant for generating combinations, not positional zips—using them for the latter will lead to massive, unintended data generation and terrible performance.
内容的提问来源于stack exchange,提问作者Bill Barrington

