I'm going through the learn you a haskell tutorial and I've been tripping over some of the examples the author has given.
For example he reimplemented zip as follows:
zip' :: [a] -> [b] -> [(a,b)]
zip' _ [] = []
zip' [] _ = []
zip' (x:xs) (y:ys) = (x,y):zip' xs ys
He uses a similar approach for all his other examples, where he puts the most specific patterns first. Here is a slightly different version of the zip function:
zip' :: [a] -> [b] -> [(a,b)]
zip' (x:xs) (y:ys) = (x, y):zip' xs ys
zip' _ _ = []
As far as I understand both methods do the same thing. If an empty list is provided either way (x:xs) or (y:ys) won't match which will finish the recursion by appending the empty list [].
Kind regards,
Edit:
Possibly duplicate of: Haskell GHC: what is the time complexity of a pattern match with N constructors?
Summary: The order of the patterns is very important for the semantics (in terms of strict evaluation of the arguments) and the readability of a function. The pattern match itself will always be in O(1) time complexity.
In Haskell pattern matching does the same thing, which they or attempt to match any given value or user passed value to the function, after this we can return any value we want or simply we can assign the value to the variable and return it.
4.4 Lazy Patterns There is one other kind of pattern allowed in Haskell. It is called a lazy pattern, and has the form ~pat. Lazy patterns are irrefutable: matching a value v against ~pat always succeeds, regardless of pat.
Haskell's case expressionprovides a way to solve this problem. Indeed, the meaning of pattern matching in function definitions is specified in the Report in terms of case expressions, which are considered more primitive. In particular, a function definition of the form: fp11... p1k=e1 fpn1... pnk=en
2) catch all block: If we do not provide the catch all block then it will throw as error, because while doing pattern matching it will not able to find anything and throw us error. If you provide the catch block then the error can be avoided also, it is safer to use also known as default pattern matching block in Haskell.
As far as I understand both methods do the same thing.
almost; with an exception:
\> zip' undefined [] -- 1st definition of zip'
[]
\> zip' (filter (< 4) [1..]) [1, 2, 3]
[(1,1),(2,2),(3,3)]
whereas:
\> zip' undefined [] -- 2nd definition of zip'
*** Exception: Prelude.undefined
\> zip' (filter (< 4) [1..]) [1, 2, 3]
[(1,1),(2,2),(3,3) -- gets stuck here; never returns
in other words, the 2nd definition always forces weak head normal form for both arguments.
Performance-wise, this means that one can construct a pathological example such that WHNF involves heavy computations, therefore one definition performs very differently than the other.
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