How to Pattern Match With Algebraic Types in Haskell - haskell

The goal of the assignment I am working on is to create a bunch of different functions that involve searching a data type called a Trie, in which the constructor is defined as
data Trie = MakeTrie Char [Trie] deriving Eq
I am tying to first build simple functions so I can figure out how to descend this Trie, but it seems like pattern matching is not working.
test :: Trie -> Bool
test t
| t == MakeTrie '.' [_] = True
| otherwise = False
I get an error stating that a hole was found and that relevant bindings include t :: Trie. How can I let the interpreter know that [_] represents a list of Tries? The reason I am doing this is because I have no idea how else do go ahead descending my Trie later if I don't use pattern matching.

You should checkout the function syntax chapter in Learn You A Haskell (particularly the first section on pattern matching).
This is how you do pattern matching in Haskell for this example:
test :: Trie -> Bool
test (MakeTrie '.' _) = True
test _ = False
Testing:
Prelude> test (MakeTrie '.' [])
True
Prelude> test (MakeTrie 'a' [])
False

There are two problems here:
if you write [_], this is a pattern that says "a list of one element, regardless what that element is"; and
you can not do pattern matching with (==).
Indeed (==) is a function that compares two objects. But it is not said that if two objects are equal, that these share the same constructor, etc. (==) can implement an arbitrary equivalence relation.
We can write the function as:
test :: Trie -> Bool
test (MakeTrie '.' _) = True
test _ = False
So here the first clause checks if the input matches the pattern MakeTrie '.' _, so it checks if it is the MakeTrie data constructor where the first parameter is a '.', the second parameter can by anything.
The second clause matches everything, and returns False in that case.

Related

How to check if all the element in the list of one algebraic type in Haskell?

If I have following algebraic data type
type MyVal = Either String Int
and have a list containing element of type MyVal
ls = [Right 1, Right 2, Right 3]
xs = [Right 1, Left "error", Right 3]
now, I want write function to find out that is my list having all the value of 'Right' then it should return True otherwise False.
In case of ls it will return True and for xs it will return False.
How can I do that?
I have tried using all function but could not able to use it correctly.
Not to gainsay all isRight as a good answer to the question which was asked, I'd question the question, to some extent. What good is it to compute, as a Bool, whether all the Either values in a list are Right? What does it enable you to do? One answer is that it entitles you to strip the Right tags from the entire list, treating the whole as error free.
A more informative option might be to construct something of type
[Either String Int] -> Either String [Int]
so that instead of a mere True or False, you obtain all the Ints untagged or the message associated with the first pesky Left.
And there is a standard function which does this (and many other things besides). It exploits the fact that lists are a data structure with a standard traversal pattern and that Either String encodes a notion of error-managing computation with standard patterns of failure and success propagation. The type has already done the hard work. All you need to say is...
sequenceA
You can make use of the isRight :: Either a b -> Bool function to check if an Either a b value is a Right x.
So you can implement this with:
import Data.Either(isRight)
allRight :: Foldable f => f (Either a b) -> Bool
allRight = all isRight
This gives us the expected output:
Prelude Data.Either> allRight ls
True
Prelude Data.Either> allRight xs
False

Pattern matching in Haskell case statements

I came across the following piece of code:
lala :: [[Int]] -> Bool
lala b = case b of
(a:_) | Just (b, _) <- uncons a -> True
other -> False
While I understand that the function checks that the first element of the list is not empty (there are better ways of writing this, but that's not the point), I don't fully understand the pattern matching happening in the case statement. Is the left arrow in this case simply pattern matching on the uncons call? Can this style of pattern matching be nested? This almost seems like a list comprehension syntax, are there other places where this type of pattern matching can be used?

Implementation of null function

I have to learn Haskell for university and therefor I'm using learnyouahaskell.com for the beginning.I always used imperative languages so I decided to practice Haskell by coding a lot more than I would for other languages.
I started to implement several functions to work with lists such as head, tail, init,...
At some point I looked up the implementations of these functions to compare to mine and I stumbled upon the null function defined in List.lhs.
null's implementation:
-- | Test whether a list is empty.
null :: [a] -> Bool
null [] = True
null (_:_) = False
my implementation:
mNull :: [a] -> Bool
mNull [] = True
mNull _ = False
I know there are no stupid questions even for such simple questions :)
So my question is why the original implementation uses (_:_) instead of just _?
Is there any advantage in using (_:_) or are there any edge cases I don't know of?
I can't really imagine any advantage because _ catches everything.
You can't just turn the clauses around with your solution:
mNull' :: [a] -> Bool
mNull' _ = False
mNull' [] = True
this
will always yield False, even if you pass an empty list. Because the runtime doesn't ever consider the [] clause, it immediately sees _ matches anything. (GHC will warn you about such an overlapping pattern.)
On the other hand,
null' :: [a] -> Bool
null' (_:_) = False
null' [] = True
still works correctly, because (_:_) fails to match the particular case of an empty list.
That in itself doesn't really give the two explicit clauses an advantage. However, in more complicated code, writing out all the mutually excluse options has one benefit: if you've forgotten one option, the compiler can also warn you about that! Whereas a _ can and will just handle any case not dealt with by the previous clauses, even if that's not actually correct.
Because _ literally means anything apart from explicitly specified patterns. When you specify (_:_) it means anything which can be represented as a list containing at least 1 element, without bothering with what or even how many elements the list actually contains. Since the case with an explicit pattern for empty list is already present, (_:_) might as well be replaced by _.
However, representing it as (_:_) gives you the flexibility to not even explicitly pass the empty list pattern. In fact, this will work:
-- | Test whether a list is empty.
null :: [a] -> Bool
null (_:_) = False
null _ = True
Demo
I'll add on to what leftaroundabout said. This is not really a potential concern for the list type, but in general, data types sometimes get modified. If you have an ill-conceived
data FavoriteFood = Pizza
| SesameSpinachPancake
| ChanaMasala
and later you learn to like DrunkenNoodles and add it to the list, all your functions that pattern match on the type will need to be expanded. If you've used any _ patterns, you will need to find them manually; the compiler can't help you. If you've matched each thing explicitly, you can turn on -fwarn-incomplete-patterns and GHC will tell you about every spot you've missed.

View patterns vs. pattern guards

I'm trying to get a sense of the relationship between view patterns and pattern guards in GHC. Pattern guards seem quite intuitive, while view patterns seem a bit confusing. It kind of looks like view patterns are better for dealing with things deep in a pattern, while pattern guards can reuse a view more intuitively, but I don't quite get it.
View patterns have significant overlap with pattern guards. The main advantage of view patterns is that they can be nested, and avoid introducing intermediate pattern variables. For a silly example:
endpoints (sort -> begin : (reverse -> end : _)) = Just (begin, end)
endpoints _ = Nothing
The pattern guard equivalent requires every new view to bind a new pattern variable, alternating between evaluating expressions and binding patterns.
endpoints xs
| begin : sorted <- sort xs
, end : _ <- reverse sorted
= Just (begin, end)
| otherwise = Nothing
View patterns can also use only those variables bound earlier in the pattern, but it does look nice:
nonzero :: (a -> Int) -> a -> Maybe a
nonzero f (f -> 0) = Nothing
nonzero _ x = Just x
-- nonzero (fromEnum . not . null) "123" == Just "123"
-- "" == Nothing
The main advantage of pattern guards is that they are a simple generalisation of guards, and can include ordinary Boolean expressions. I generally prefer them over view patterns because I find the style of case and guards less repetitious than the equational style.
View patterns let you project a value before pattern matching on it. It can almost be thought of as a short cut for
foo x = case f x of
...
There's a bit of sugar on top for dealing with more complex views, but basically that's it. On the other hand, pattern guards are strictly more general,
They can include arbitrary boolean conditions for matching
They can match using more than one of the variables
I favor view patterns when I'm doing something "lens-like". I have a big piece of data and I'm interested in one particular view of it. For example, with lens
foo (view someLens -> Bar baz quux) = ...
Pattern guards tend to work well when you want something closer to a more flexible case expression.

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