Pattern matching on function application in a pattern match? - haskell

I'd like to pattern match against a value returned from function application. For instance:
If I have a Map and I'd like to alternate on a key being in that map, do I have a better option than:
f map k = case map !? k of
Just _ -> foo
Nothing -> bar
In this particular case I could just as easily use member and guard, like:
f map k | member k map = foo
| otherwise = bar
but would prefer to use pattern matching in some cases.

Your first example does use pattern matching, but just in a case expression. But I think what you're looking for is the ViewPatterns extension, which can be useful for eliminating boilerplate (in particular in a case expression, where you can use both pattern matching and guards together).
{-# LANGUAGE ViewPatterns #-}
f k ((!? k)-> Just _) = foo
f _ _ = bar
Notice though that you need to switch the order of the arguments in order for k to be in scope in the view pattern for the seconds argument.
But I don't think this is better than your first version of f.

Related

Haskell: "Qualified name in binding position" error with Map.empty

I'm trying to create a pattern synonym for a newtype with an empty map.
{-# Language PatternSynonyms #-}
import qualified Data.Map as Map
newtype StoreEnv = StoreEnv (Map.Map Int String)
deriving (Eq, Show)
pattern EmptyStore :: StoreEnv
pattern EmptyStore = StoreEnv Map.empty
I got an error saying "Qualified name in binding position: Map.empty" when compiling this. I believe that "Map.empty" should belong to the type "Map.Map Int String" that I declare in the newtype.
My question is whether there is a way to alias an empty map correctly.
I would appreciate any feedback.
Background
So you cannot pattern match against maps like you would do with list then.
That's right. Data.Map.Map is an abstract data type, meaning that its representation is hidden. In Haskell that means its constructors aren't exported. You can't write code which inspects the balanced binary search tree inside the Map (and you wouldn't want to anyway) - you have to go through its public interface, using the module's exported functions to create, query and manipulate Maps.
Pattern synonyms exist to bridge the gap between ADT programming and the convenient syntax of pattern matching on the left of an equation. You can define some smart patterns as part of your module's API without necessarily coupling the implementation of your ADT to those patterns.
Your problem
You're getting that error because syntactically the right-hand side of a pattern synonym has to be a pattern, not an expression. A pattern is (usually) the name of a value constructor applied to some variable binders - that is, in a definition like
getBar (Foo bar baz) = bar
the bar and baz on the left-hand side define variables which will be in scope on the right. They are fresh bindings, not references to any bar or baz variables which may exist in some outer scope.
So I think that as well as the syntactic mistake (Map.empty is not a valid name for a local variable, which is why you're getting that error) you've also made a logical one - you wouldn't have been able to refer to Map.empty in that position anyway.
The fix
As I suggested in my comment, you can patch up your code by using an explicitly bidirectional pattern synonym. This is a neat feature which lets you give a pattern synonym a different meaning depending on whether it's being used as a pattern (ie in pattern context) or as a value constructor (ie in expression context).
pattern EmptyStore <- StoreEnv (Map.null -> True)
where EmptyStore = StoreEnv Map.empty
In the first line I'm defining what EmptyStore means when used as a pattern. The Map.null -> True syntax is called a view pattern - it means "apply the function Map.null to this piece of the pattern, and match its result with True". So EmptyStore matches a StoreEnv when the Map inside the StoreEnv is empty.
The second line defines what EmptyStore does when used as an expression. It says that the expression EmptyStore is a synonym for the expression StoreEnv Map.empty - "create an empty Map and wrap it in a StoreEnv".
The un-fix
However I submit that a pattern synonym API for Map doesn't really make sense. To be usable you should really define a complete set of patterns, so that users have a way to deconstruct any type of Map. The empty case is easy to handle, because there's only one empty Map, but what does it mean to pattern match on a non-empty Map? Maps aren't meant to be ordered containers - there's no "first-and-rest" like there is with [], so this doesn't make sense:
pattern Cons k v rest <- {- what goes here? -}
where Cons k v rest = insert k v rest
You might instead try to define a pattern which matches when a particular key is present in the map:
pattern Contains k v <- (lookup k -> Just v)
but this is not valid Haskell (k is being referred to, when it should be being bound). Even if you could come up with a clever way to express it, such a set of patterns would necessarily be incomplete because you can't write clauses for every possible key.
In other words, I don't think you should be trying to define pattern synonyms for this datatype. Stick with ordinary functions!

Pattern matching over Data.Map

I did a search but, surprisingly, didn't find anything that would help me to perform pattern matching over it. I need to make sure that in my Map "variable" exactly 3 keys. That's it. Instead of "if ... then ... else", I want to go with pattern matching as it is easier to read and seems to be more haskell way. So:
myFunction :: Map String String
--.......................
main = do
let var1 = myFunction
-- how do I ensure it has exactly 3 keys in it and if not raise an error?
You cannot pattern match on abstract data types, as you don’t have access to their constructors¹, so you will have to work with the functions provided by the `Data.Map´ module.
But note that there is a size :: Map k a -> Int function you can use. And if you don’t like if .. then .. else .. (which is in no way wrong or unhaskellish), you can use pattern guards:
foo m | size m == 3 = ...
| otherwise = error "Not three element"
¹ Disregarding view patterns and pattern synonyms here, but these are just syntactic surgar.
You could pattern match on M.toList:
import qualified Data.Map as M
-- ...
main = do
case (M.toList myFunction) of
[a,b,c] -> ... -- exactly 3 arguments
_ -> ... -- more or less than 3 arguments

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.

function parameters in haskell

I can use parenthesis to make cons operator have more priority than function application in this patter match equation:
tail (_:xs) = xs
However it will be "parse error in pattern" if I try to write this:
f (g x) = 7
I see that g x produces a value and we should directly pass that value. Or in this way f g x = g x + 7 we make a call to g with an argument x in the body of f definition.
But what is the reason for not allowing to pass a function call in the pattern?
A pattern match is about destructuring things. Think along the lines of "I have build this data using constructor A". With pattern matching we could see what values we supplied A.
This means that means that constructors have to be invertible, we need to be able to figure out a constructors inputs given the results. Now if you wanted to do the same thing with a function call you'd be in trouble since you can't just invert a function, imagine f = const 0.
What it sounds like you want instead is a view pattern. This is where you are passed data, feed it into a function, and then pattern match on the result.
{-# LANGUAGE ViewPatterns #-}
foo (bar -> Just a) = a
This should be read as "Feed the argument to bar, then pattern match on the resulting Maybe".
We don't pass anything in a pattern. We describe how data that is passed must look like for the corresponding equation to take effect.
Now, it turns out that every value is of the form g x for some combination of g and x, so the pattern g x can be abbreviated to just x.

Haskell pattern matching symmetric cases

Suppose I have a haskell expression like:
foo (Nothing, Just a) = bar a
foo (Just a, Nothing) = bar a
Is there any haskell syntax to collapse those cases, so I can match either pattern and specify bar a as the response for both? Or is that about as succinct as I can get it?
If your code is more complex than your example, you might want to do something like this, using the Alternative instance for Maybe and the PatternGuards extension (part of Haskell2010).
{-# LANGUAGE PatternGuards #-}
import Control.Applicative
foo (x, y) | Just a <- y <|> x = bar a
In case you are not familiar with it, <|> picks the left-most Just if there is one and returns Nothing otherwise, causing the pattern guard to fail.
That's as succinct as it gets in Haskell. In ML there is a syntax for what you want (by writing multiple patterns, which bind the same variables, next to each other separated by | with the body after the last pattern), but in Haskell there is not.
You can use -XViewPatterns, to add arbitrary functions to collapse your two cases into a single pattern.
Your pattern is now a function p that yields the thing you want to match:
foo (p -> (Just a, Nothing)) = bar a
much simpler!
We have to define p though, as:
p (Nothing, a#(Just _)) = (a, Nothing)
p a#(Just _, Nothing) = a
p a = a
or however you wish to normalize the data before viewing.
References: The GHC User's Guide chapter on View Patterns

Resources