A real life example when pattern matching is more preferable than a case expression in Haskell? - haskell

So I have been busy with the Real World Haskell book and I did the lastButOne exercise. I came up with 2 solutions, one with pattern matching
lastButOne :: [a] -> a
lastButOne ([]) = error "Empty List"
lastButOne (x:[]) = error "Only one element"
lastButOne (x:[x2]) = x
lastButOne (x:xs) = lastButOne xs
And one using a case expression
lastButOneCase :: [a] -> a
lastButOneCase x =
case x of
[] -> error "Empty List"
(x:[]) -> error "Only One Element"
(x:[x2]) -> x
(x:xs) -> lastButOneCase xs
What I wanted to find out is when would pattern matching be preferred over case expressions and vice versa. This example was not good enough for me because it seems that while both of the functions work as intended, it did not lead me to choose one implementation over the other. So the choice "seems" preferential at first glance?
So are there good cases by means of source code, either in haskell's own source or github or somewhere else, where one is able to see when either method is preferred or not?

First a short terminology diversion: I would call both of these "pattern matching". I'm not sure there is a good term for distinguishing pattern-matching-via-case and pattern-matching-via-multiple-definition.
The technical distinction between the two is quite light indeed. You can verify this yourself by asking GHC to dump the core it generates for the two functions, using the -ddump-simpl flag. I tried this at a few different optimization levels, and in all cases the only differences in the Core were naming. (By the way, if anyone knows a good "semantic diff" program for Core -- which knows about at the very least alpha equivalence -- I'm very interested in hearing about it!)
There are a few small gotchas to watch out for, though. You might wonder whether the following is also equivalent:
{-# LANGUAGE LambdaCase #-}
lastButOne = \case
[] -> error "Empty List"
(x:[]) -> error "Only One Element"
(x:[x2]) -> x
(x:xs) -> lastButOneCase xs
In this case, the answer is yes. But consider this similar-looking one:
-- ambiguous type error
sort = \case
[] -> []
x:xs -> insert x (sort xs)
All of a sudden this is a typeclass-polymorphic CAF, and so on old GHCs this will trigger the monomorphism restriction and cause an error, whereas the superficially identical version with an explicit argument does not:
-- this is fine!
sort [] = []
sort (x:xs) = insert x (sort xs)
The other minor difference (which I forgot about -- thank you to Thomas DuBuisson for reminding me) is in the handling of where clauses. Since where clauses are attached to binding sites, they cannot be shared across multiple equations but can be shared across multiple cases. For example:
-- error; the where clause attaches to the second equation, so
-- empty is not in scope in the first equation
null [] = empty
null (x:xs) = nonempty
where empty = True
nonempty = False
-- ok; the where clause attaches to the equation, so both empty
-- and nonempty are in scope for the entire case expression
null x = case x of
[] -> empty
x:xs -> nonempty
where
empty = True
nonempty = False
You might think this means you can do something with equations that you can't do with case expressions, namely, have different meanings for the same name in the two equations, like this:
null [] = answer where answer = True
null (x:xs) = answer where answer = False
However, since the patterns of case expressions are binding sites, this can be emulated in case expressions as well:
null x = case x of
[] -> answer where answer = True
x:xs -> answer where answer = False
Whether the where clause is attached to the case's pattern or to the equation depends on indentation, of course.

If I recall correctly both these will "desugar" into the same core code in ghc, so the choice is purely stylistic. Personally I would go for the first one. As someone said, its shorter, and what you term "pattern matching" is intended to be used this way. (Actually the second version is also pattern matching, just using a different syntax for it).

It's a stylistic preference. Some people sometimes argue that one choice or another makes certain code changes take less effort, but I generally find such arguments, even when accurate, don't actually amount to a big improvement. So do as you like.
A perspective that's well worth bringing into this is Hudak, Hughes, Peyton Jones and Wadler's paper "A History of Haskell: Being Lazy With Class". Section 4.4 is about this topic. The short story: Haskell supports both because the designers couldn't agree on one over the other. Yep, again, it's a stylistic preference.

When you're matching on more than one expression, case expressions start to look more attractive.
f pat11 pat21 = ...
f pat11 pat22 = ...
f pat11 pat23 = ...
f pat12 pat24 = ...
f pat12 pat25 = ...
can be more annoying to write than
f pat11 y =
case y of
pat21 -> ...
pat22 -> ...
pat23 -> ...
f pat12 y =
case y of
pat24 -> ...
pat25 -> ...
More significantly, I've found that when using GADTs, the "declaration style" doesn't seem to propagate evidence from left to right the way I'd expect it to. There might be some trick I haven't worked out, but I end up having to nest case expressions to avoid spurious incomplete pattern warnings.

Related

What, in Haskell, does an underscore preceding a variable mean?

I was browsing the source of Data.Foldable, where I came accross Endo #. f, and upon clicking this link, was confronted with:
(#.) _f = coerce
Now, first, I don't know what coerce and the before-that mentioned Coercible is, however, it baffles me more what the _f could mean. I have searched "Haskell underscore before variable" and similar and have only found discussions about the _ pattern matching syntax.
According to the Haskell spec, it is just another possible name for a variable. But the truth is a bit longer, because most Haskell developers write code specifically for GHC, and this is one of those times.
GHC has lots of helpful warnings; one is to warn you when you write a pattern that binds a variable that isn't used in the body of the function. It's pretty handy, and has caught a couple bugs of mine. However, it has a knock-on effect: if you write a function that uses some of the variables only in one clause or the other, you get a warning. For example, here is a very natural definition of foldr on lists:
foldr f z [] = z
foldr f z (x:xs) = x `f` foldr f z xs
Oops! We didn't use f in the first clause, and we'll get a warning. Okay, so it's easy enough to fix:
foldr _ z [] = z
foldr f z (x:xs) = x `f` foldr f z xs
Unfortunately now we've lost the information about what that first variable's role in the code is supposed to be. In this case, foldr is so familiar that it's no big loss, but in unfamiliar codebases with functions that take a lot of arguments, it can be nice to know what data is ignored by each "hole". So GHC adds a special rule: the warning about unused variables doesn't warn you about variable names that start with _ -- by analogy to the _ pattern that it also doesn't warn you about. So now I can write:
foldr _f z [] = z
foldr f z (x:xs) = x `f` foldr f z xs
Now I get the best of both worlds: I get a nice warning if I forget to use a variable I bound, and I can still give the reader information about the meaning of the holes in patterns that I don't need for the current clause. (As a side note, I'd love an additional warning that reported if I do mistakenly use a variable starting with _, but I don't think it exists at the moment! It sounds stupid ("just don't type _ in a function body"), but I've found my editor's tab-completion occasionally inserting them for me, and it would be easy not to notice if you were coding quickly.)
It's just a convention to mark an unused variable. As you see, _f isn't used in the definition of #., so it is marked with the underscore.

Error: Non-exhaustive patterns in function Haskell

I did a thread for an error like this one, in it I explain my program. here's the link
I'm going forward in my project and I have an another problem like that one. I did an other thread but if I just need to edit the first one just tell me.
I want to reverse my matrix. For example [[B,B,N],[N,B,B]] will become [[B,N],[B,B],[N,B]]. Here's my code:
transpose :: Grille -> Grille
transpose [] = []
transpose g
| head(g) == [] = []
| otherwise = [premierElem(g)] ++ transpose(supp g)
supp :: Grille -> Grille
supp [] = []
supp (g:xg) = [tail(g)] ++ supp(xg)
premierElem :: Grille -> [Case]
premierElem [] = []
premierElem (x:xg) = [head(x)] ++ premierElem(xg)
I got the exact same error and I tried like for the first one but that's not it.
EDIT: The exact error
*Main> transpose g0
[[B,B,N,B,N,B],[B,B,B,B,N,B],[B,N,N,B,N,B],[B,B,N,N,B,N],[B,N,N,N,B,N],[B,B,N,B,B,B],[N,B,N,N,B,N],[*** Exception: Prelude.head: empty list
The problem is that your transpose function has a broken termination condition. How does it know when to stop? Try walking through the final step by hand...
In general, your case transpose [] = [] will never occur, because your supp function never changes the number of lists in its argument. A well-formed matrix will end up as [[],[],[],...], which will not match []. The only thing that will stop it is an error like you received.
So, you need to check the remaining length of your nested (row?) vectors, and stop if it is zero. There are many ways to approach this; if it's not cheating, you could look at the implementation of transpose in the Prelude documents.
Also, re your comment above: if you expect your input to be well-formed in some way, you should cover any excluded cases by complaining about the ill-formed input, such as reporting an error.
Fixing Your Code
You should avoid using partial functions, such as tail and head, and instead make your own functions do (more) pattern matching. For example:
premierElem g = [head(head(g))] ++ premierElem(tail(g))
Yuck! If you want the first element of the first list in g then match on the pattern:
premierElem ((a:_):rest) = [a] ++ premierElem rest
This in and of itself is insufficient, you'll want to handle the case where the first list of the Grille is an empty list and at least give a useful error message if you can't use a reasonable default value:
premeirElem ([]:rest) = premeirElem rest
Making Better Code
Eventually you will become more comfortable in the language and learn to express what you want using higher level operations, which often means you'll be able to reuse functions already provided in base or other libraries. In this case:
premeirElem :: [[a]] -> [a]
premeirElem = concatMap (take 1)
Which assumes you are OK with silently ignoring []. If that isn't your intent then other similarly concise solutions can work well, but we'd need clarity on the goal.

"For all" statements in Haskell

I'm building comfort going through some Haskell toy problems and I've written the following speck of code
multipOf :: [a] -> (Int, a)
multipOf x = (length x, head x)
gmcompress x = (map multipOf).group $ x
which successfully preforms the following operation
gmcompress [1,1,1,1,2,2,2,3] = [(4,1),(3,2),(1,3)]
Now I want this function to instead of telling me that an element of the set had multiplicity 1, to just leave it alone. So to give the result [(4,1),(3,2),3] instead. It be great if there were a way to say (either during or after turning the list into one of pairs) for all elements of multiplicity 1, leave as just an element; else, pair. My initial, naive, thought was to do the following.
multipOf :: [a] -> (Int, a)
multipOf x = if length x = 1 then head x else (length x, head x)
gmcompress x = (map multipOf).group $ x
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
Your diagnosis is right; the then and else must have the same type. There's no "getting past this issue," strictly speaking. Whatever solution you adopt has to use same type in both branches of the conditional. One way would be to design a custom data type that encodes the possibilities that you want, and use that instead. Something like this would work:
-- | A 'Run' of #a# is either 'One' #a# or 'Many' of them (with the number
-- as an argument to the 'Many' constructor).
data Run a = One a | Many Int a
But to tell you the truth, I don't think this would really gain you anything. I'd stick to the (Int, a) encoding rather than going to this Run type.

In Haskell, why non-exhaustive patterns are not compile-time errors?

This is a follow-up of Why am I getting "Non-exhaustive patterns in function..." when I invoke my Haskell substring function?
I understand that using -Wall, GHC can warn against non-exhaustive patterns. I'm wondering what's the reason behind not making it a compile-time error by default given that it's always possible to explicitly define a partial function:
f :: [a] -> [b] -> Int
f [] _ = error "undefined for empty array"
f _ [] = error "undefined for empty array"
f (_:xs) (_:ys) = length xs + length ys
The question is not GHC-specific.
Is it because...
nobody wanted to enforce a Haskell compiler to perform this kind of analysis?
a non-exhaustive pattern search can find some but not all cases?
partially defined functions are considered legitimate and used often enough not to impose the kind of construct shown above? If this is the case, can you explain to me why non-exhaustive patterns are helpful/legitimate?
There are cases where you don't mind that a pattern match is non-exhaustive. For example, while this might not be the optimal implementation, I don't think it would help if it didn't compile:
fac 0 = 1
fac n | n > 0 = n * fac (n-1)
That this is non-exhaustive (negative numbers don't match any case) doesn't really matter for the typical usage of the factorial function.
Also it might not generally be possible to decide for the compiler if a pattern match is exhaustive:
mod2 :: Integer -> Integer
mod2 n | even n = 0
mod2 n | odd n = 1
Here all cases should be covered, but the compiler probably can't detect it. Since the guards could be arbitrarily complex, the compiler cannot always decide if the patterns are exhaustive. Of course this example would better be written with otherwise, but I think it should also compile in its current form.
You can use -Werror to turn warnings into errors. I don't know if you can turn just the non-exhaustive patterns warnings into errors, sorry!
As for the third part of your question:
I sometimes write a number of functions which tend to work closely together and have properties which you can't easily express in Haskell. At least some of these functions tend to have non-exhaustive patterns, usually the 'consumers'. This comes up, for example in functions which are 'sort-of' inverses of each other.
A toy example:
duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) = x : x : (duplicate xs)
removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates [] = []
removeDuplicates (x:y:xs) | x == y = x : removeDuplicates xs
Now it's pretty easy to see that removeDuplicates (duplicate as) is equal to as (whenever the element type is in Eq), but in general duplicate (removeDuplicates bs) will crash, because there are an odd number of elements or 2 consecutive elements differ. If it doesn't crash, it's because bs was produced by (or could have been produced by) duplicate in the first place!.
So we have the following laws (not valid Haskell):
removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)
Now, if you want to prevent non-exhaustive patterns here, you could make removeDuplicates return Maybe [a], or add error messages for the missing cases. You could even do something along the lines of
newtype DuplicatedList a = DuplicatedList [a]
duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted
All this is necessary, because you can't easily express 'being a list of even length, with consecutive pairs of elements being equal' in the Haskell type system (unless you're Oleg :)
But if you don't export removeDuplicates I think it's perfectly okay to use non-exhaustive patterns here. As soon as you do export it, you'll lose control over the inputs and will have to deal with the missing cases!

Is it recommended to always have exhaustive pattern matches in Haskell, even for "impossible" cases?

Is it recommended to always have exhaustive pattern matches in Haskell, even for "impossible" cases?
For example, in the following code, I am pattern matching on the "accumulator" of a foldr. I am in complete control of the contents of the accumulator, because I create it (it is not passed to me as input, but rather built within my function). Therefore, I know certain patterns should never match it. If I strive to never get the "Pattern match(es) are non-exhaustive" error, then I would place a pattern match for it that simply error's with the message "This pattern should never happen." Much like an assert in C#. I can't think of anything else to do there.
What practice would you recommend in this situation and why?
Here's the code:
gb_groupBy p input = foldr step [] input
where
step item acc = case acc of
[] -> [[item]]
((x:xs):ys) -> if p x item
then (item:x:xs):ys
else [item]:acc
The pattern not matched (as reported by the interpreter) is:
Warning: Pattern match(es) are non-exhaustive
In a case alternative: Patterns not matched: [] : _
This is probably more a matter of style than anything else. Personally, I would put in a
_ -> error "Impossible! Empty list in step"
if only to silence the warning :)
You can resolve the warning in this special case by doing this:
gb_groupBy p input = foldr step [] input
where
step item acc = case acc of
[] -> [[item]]
(xs:xss) -> if p (head xs) item
then (item:xs):xss
else [item]:acc
The pattern matching is then complete, and the "impossible" condition of an empty list at the head of the accumulator would cause a runtime error but no warning.
Another way of looking at the more general problem of incomplete pattern matchings is to see them as a "code smell", i.e. an indication that we're trying to solve a problem in a suboptimal, or non-Haskellish, way, and try to rewrite our functions.
Implementing groupBy with a foldr makes it impossible to apply it to an infinite list, which is a design goal that the Haskell List functions try to achieve wherever semantically reasonable. Consider
take 5 $ groupBy (==) someFunctionDerivingAnInfiniteList
If the first 5 groups w.r.t. equality are finite, lazy evaluation will terminate. This is something you can't do in a strictly evaluated language. Even if you don't work with infinite lists, writing functions like this will yield better performance on long lists, or avoid the stack overflow that occurs when evaluating expressions like
take 5 $ gb_groupBy (==) [1..1000000]
In List.hs, groupBy is implemented like this:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs
This enables the interpreter/compiler to evaluate only the parts of the computation necessary for the result.
span yields a pair of lists, where the first consists of (consecutive) elements from the head of the list all satisfying a predicate, and the second is the rest of the list. It's also implemented to work on infinite lists.
I find exhaustiveness checking on case patterns indispensible. I try never to use _ in a case at top level, because _ matches everything, and by using it you vitiate the value of exhaustiveness checking. This is less important with lists but critical important with user-defined algebraic data types, because I want to be able to add a new constructor and have the compiler barf on all the missing cases. For this reason I always compile with -Werror turned on, so there is no way I can leave out a case.
As observed, your code can be extended with this case
[] : _ -> error "this can't happen"
Internally, GHC has a panic function, which unlike error will give source coordinates, but I looked at the implementation and couldn't make head or tail of it.
To follow up on my earlier comment, I realised that there is a way to acknowledge the missing case but still get a useful error with file/line number. It's not ideal as it'll only appear in unoptimized builds, though (see here).
...
[]:xs -> assert False (error "unreachable because I know everything")
The type system is your friend, and the warning is letting you know your function has cracks. The very best approach is to go for a cleaner, more elegant fit between types.
Consider ghc's definition of groupBy:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs
My point of view is that an impossible case is undefined.
If it's undefined we have a function for it: the cunningly named undefined.
Complete your matching with the likes of:
_ -> undefined
And there you have it!

Resources