View patterns vs. pattern guards
Asked Answered
P

3

17

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.

Potty answered 24/12, 2013 at 21:17 Comment(0)
A
16

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.

Acrylonitrile answered 24/12, 2013 at 22:6 Comment(0)
M
9

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,

  1. They can include arbitrary boolean conditions for matching
  2. 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.

Mehala answered 24/12, 2013 at 21:49 Comment(0)
G
0

I'm not sure about pattern guards but I just learned how to use View patterns.

I found this helpful https://blog.ocharles.org.uk/posts/2014-12-02-view-patterns.html but most of the other documentation was next to useless

I had a type like this

data DiffInformation {
  firstField :: [Int]
, secondField :: [Int]
, thirdField :: [Int]
}

and a function that was doing this

doStuff :: DiffInformation -> SomeState -> SomeState
doStuff (DiffInformation [] [] []) state = state
doStuff DiffInformation{..} state = undefined -- something more interesting

I needed to add a HashMap to DiffInformation but didn't want to move away from a pattern match and add a case statement/indent everything in the more interesting case.

You don't have access to HashMap's constructor to pattern match and so you have to use a function call to tell whether a HashMap is empty. That function is null :: HashMap k v -> Bool

So I did this

data DiffInformation {
  firstField :: [Int]
, secondField :: [Int]
, thirdField :: [Int]
, newField :: HashMap Int String
}
doStuff :: DiffInformation -> SomeState -> SomeState
doStuff (DiffInformation [] [] [] (HashMap.null -> True) state = state
doStuff DiffInformation{..} state = undefined -- something more interesting

You can name the parameter if you need to as well, although it isn't useful in this example

doStuff (DiffInformation [] [] [] (\theNewField -> HashMap.null theNewField -> True) state = state
Govea answered 20/5, 2024 at 15:45 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.