[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