[Haskell-cafe] Pattern guards seen in the wild?

Tom Smeding x at tomsmeding.com
Fri Oct 1 07:04:21 UTC 2021


On 01/10/2021 07:29, Viktor Dukhovni wrote:
> More realistic examples:
>
>      https://github.com/kazu-yamamoto/dns/blob/master/internal/Network/DNS/Decode/Parsers.hs#L46-L49
>
> Or code to process a possibly not yet complete (to be continued) SMTP
> greeting:
>
>      smtpGreeting :: Int -> SmtpReply -> SmtpM B.ByteString
>      smtpGreeting _ r
>          | replyCont r            = pure B.empty
>          | code <- replyCode r
>          , code `div` 100 /= 2    = B.empty <$ modify' bail code
>          | otherwise              = smtpSendHello
>        where
>          bail code s =
>              s { smtpErr = ProtoErr code $ replyText r }
>
[...]
>
> --
>      Viktor.

Perhaps redundantly, this particular instance of a pattern guard can, in
my opinion, be written slightly less suggestively with a 'let' pattern
guard (not sure if that's the right name):

     [...]
         | let code = replyCode r
         , code `div` 100 /= 2    = B.empty <$ modify' bail code
     [...]

Non-'let' pattern guards, in my experience, are most useful in two cases:

1. You want to do some additional pattern matching on a non-boolean
value after having arrived in an interesting case in a larger
pattern-match. For example, in the request URL parsing code in my
pastebin-haskell: (Some cases and additional code elided)

     parseRequest :: Method -> ByteString -> Maybe WhatRequest
     parseRequest method path =
         let comps = BS.split (fromIntegral (ord '/')) (trimSlashes path)
         in case (method, comps) of
                (GET, []) -> Just GetIndex
                (GET, [x]) | canBeKey x -> Just (ReadPaste x)
                -- [...]
                (GET, ["paste", x]) | canBeKey x -> Just (ReadPasteOld x)
                (GET, ["highlight.pack.css"]) -> Just HighlightCSS
                (GET, [x]) | Just (path', mime) <- List.lookup x
staticFiles -> Just (StaticFile mime path')
                (POST, ["paste"]) -> Just StorePaste
                _ -> Nothing

Original code here:
https://github.com/tomsmeding/pastebin-haskell/blob/25de4aa531a782ca8c34b409046b414f655f133c/Main.hs#L197

2. Actually a special case of (1.): this is particularly useful with
GADTs and "discovered" type evidence, like in
https://github.com/AccelerateHS/accelerate/blob/1ab75f1eb01a1b427563808057d46f29d99bb4dc/src/Data/Array/Accelerate/Prelude.hs#L1429
.

In general, these pattern guards seem to me the Haskell version of
Agda's with-patterns [1], which also allow pattern matching on an
_additional_ value after the first pattern match has already found a branch.

- Tom

[1]: https://agda.readthedocs.io/en/v2.5.2/language/with-abstraction.html



More information about the Haskell-Cafe mailing list