Pattern and Guard Extensions

These extensions enhance Haskell's patterns and guards.

NPlusKPatterns

Available in: Current Haskell Platform

The deprecated extension NPlusKPatterns was originally part of Haskell 98, but has since been removed in Haskell 2010. It allows a very specific extension of pattern syntax, such that you can write, e.g.:

myFunc (x+3) = f x

and have it mean exactly:

myFunc x' | x' >= 3 = let x = x'-3 in f x

(modulo naming of x', of course).

In place of 3, you can have any fixed positive integer literal (the "k" in the term "n-plus-k pattern").

Because of the extremely limited utility of this feature, and its nature as an explicit special case, n-plus-k patterns were eventually deemed unworthy of inclusion in the language and were dropped in the Haskell 2010 Report.

WARNING: Do not use NPlusKPatterns in new code! I only include it here because it may be important when trying to understand legacy Haskell codebases. If NPlusKPatterns seems like it would have been a perfect fit for your use case, try using ViewPatterns instead.

BangPatterns

Available in: Current Haskell Platform

The BangPatterns extension allows a small extension to pattern syntax. You can now write patterns of the form !p, where p is any other pattern, and have it mean "match as though by p, but first evaluate the value being matched to weak head normal form". In essence, just standard Haskell allows you to force a pattern match to be lazy (or "irrefutable") by using ~, the BangPatterns extension allows you to force a pattern match to be strict (or "immediate") by using !.

Try it out!

{-# LANGUAGE BangPatterns #-}

lazyFunc, strictFunc :: () -> ()

-- lazy, even though it would normally be strict
lazyFunc ~() = ()

-- strict, even though it would normally be lazy
strictFunc !v = ()

-- replace 'lazyFunc' with 'strictFunc' and see what happens
main = print $ lazyFunc undefined

ViewPatterns

Available in: Current Haskell Platform

The ViewPatterns extension adds a new form of pattern that can be used anywhere any other pattern can, and that applies an arbitrary expression (of appropriate function type), called a view, to the argument before matching. A view pattern e -> p applies the view e to the argument that would be matched by the whole view pattern, and then matches the pattern p against e's result. The whole view pattern matches against the original value exactly when p matches against the derived value. A consequence of these semantics is that e -> p is irrefutable exactly when p is irrefutable, as long as e is sufficiently lazy.

Try it out!

{-# LANGUAGE ViewPatterns #-}

eitherEndIsZero :: [Int] -> Bool
eitherEndIsZero (head -> 0) = True
eitherEndIsZero (last -> 0) = True
eitherEndIsZero          _  = False

main = print $ eitherEndIsZero [0,1,8,9]

ViewPatterns as a Replacement for NPlusKPatterns

You can use ViewPatterns to replace the deprecated NPlusKPatterns by simply using subtract k as the view. Although it is somewhat longer to type, it affords greater future-proofing and less fragility than NPlusKPatterns does:

myFunc x'@(subtract 3 -> x) | x' >= 3 = f x

PatternGuards

Available in: Current Haskell Platform

The PatternGuards extension, now officially incorporated into the Haskell 2010 language, expands guards to allow arbitrary pattern matching and condition chaining. The existing syntax for guards then becomes a special case of the new, much more general form.

You start a guard the same as always, with a |. You then follow with either a boolean guardlet or a pattern guardlet. A boolean guardlet is any expression whose type is Bool, and they function as before. A pattern guardlet is of the form p <- e, where p is an arbitrary pattern and e is an arbitrary expression, and which is fullfilled exactly when e matches against p. You may then add additional boolean or pattern guardlets, seperated from each other by commas. Finally, you finish off the complete guard with =, as usual.

PatternGuards syntax is deliberately designed to be reminicent of list comprehension syntax, but be aware that, in a pattern guardlet, p matches against the same type as e, unlike in a list comprehension generator. All the provided guardlets are tried in order, and only if all of them succeed is that guard's clause chosen. Otherwise, evaluation moves to the next clause down, as usual (or unceremoniously falls off the bottom if there is no next clause, also as usual).

Try it out!

{-# LANGUAGE PatternGuards #-}
import Data.List (nub)

strangeOperation :: [Int] -> Ordering
strangeOperation xs | 7  <- sum xs
                    , n  <- length xs
                    , n  >= 5
                    , n  <= 20
                      = EQ
                    | 1  <- sum xs
                    , 18 <- length xs
                    , r  <- nub xs `compare` [1,2,3]
                    , r /= EQ
                      = r
                    | otherwise
                      = [3,1,2] `compare` xs

main = print $ strangeOperation ([5,7..21] ++ [20,19..4])