What are the performance benefits of using ~ (lazy pattern matching) in Data.List's partition. Contrived examples of lazy pattern matching suggest that it is useful when the values inside the tuple constructor are never used (f (x,y) = 1). In partition (select, below), the lists ts, fs are always used (if the predicate p applied to x is True, or not). I'm sure this is a very well informed decision to use ~, but what is the point? Why not strict pattern matching?
partition :: (a -> Bool) -> [a] -> ([a],[a])
{-# INLINE partition #-}
partition p xs = foldr (select p) ([],[]) xs
select :: (a -> Bool) -> a -> ([a], [a]) -> ([a], [a])
select p x ~(ts,fs) | p x = (x:ts,fs)
| otherwise = (ts, x:fs)
(Note: I've already looked here! it doesn't answer the above question)
Python 3.10 match statements are faster at pattern matching sequences than equivalent if-statements. MUCH faster. The second functions runs 86% faster than the first.
Pattern matching consists of specifying patterns to which some data should conform and then checking to see if it does and deconstructing the data according to those patterns. When defining functions, you can define separate function bodies for different patterns.
The pattern-matching algorithm uses a variety of techniques to match different kinds of expression. Data elements such as numbers, strings, booleans are matched by comparison: a pattern consisting of a single data element matches only that exact element.
Pattern matching comes up in several places in OCaml: as a powerful control structure combining a multi-armed conditional, unification, data destructuring and variable binding; as a shortcut way of defining functions by case analysis; and as a way of handling exceptions.
The point is that with strict pattern matching, assembling of the result could only start when the end of the list to be partitioned has been reached, in particular, partition
would not work at all for infinite lists.
With a strict pattern match, the argument must be evaluated to WHNF. That means the entire foldr
of the tail must have finished before it is decided whether x
is put in the first or the second component.
select p x (foldr (select p) ([],[]) (y:z:ws))
~> select p x (select p y (select p z (foldr (select p) ([],[]) ws)))
With a lazy pattern match, a pair is constructed immediately, with x
as the first element of the appropriate component, and the rest of the two lists to be evaluated later, when needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With