
On Fri, Oct 01, 2021 at 04:06:45PM +1300, Anthony Clayden wrote:
Browsing some docos for a completely other purpose, I came across this code:
f' [x, y] | True <- x, True <- y = True f' _ = False
(In User Guide 6.7.4.5 Matching of Pattern Synonyms.)
A fairly synthetic exmaple...
In 10 years of reading Haskell code, I've never seen them. Does anybody use them? Are they more ergonomic than guards as plain Boolean expressions? Are 'local bindings' any different vs shunting the `let` to the rhs of the `=`?
The pattern guards in the example are far from compelling as written, but I do regularly use them in I hope more natural contexts.
I'd write that code as:
f'' [x@True, y@True] = True f'' _ = False
Or with no guards at all: f'' [x, y] = x && y f'' _ = False More realistic examples: https://github.com/kazu-yamamoto/dns/blob/master/internal/Network/DNS/Decode... 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 } which would otherwise be something like: smtpGreeting :: Int -> SmtpReply -> SmtpM B.ByteString smtpGreeting _ r = if replyCont r then pure B.empty else let code = replyCode r in if code `div` 100 == 2 then smtpSendHello else B.empty <$ modify' bail code where bail code s = s { smtpErr = ProtoErr code $ replyText r } but I find the pattern guard form to read "declarative", with less "if then else" baggage and nesting getting in the way of seeing the essential conditions. -- Viktor.