The following
(&&) :: Bool -> Bool -> Bool
False && _ = False
True && False = False
True && True = True
has the desired short-circuit property False && undefined ≡ False
. The first clause, which is non-strict in the right argument, is guaranteed to be checked before anything else is tried.
Apparently, it still works if I change the order and even uncurry the function
both :: (Bool,Bool) -> Bool
both (True,False) = False
both (True, True) = True
both (False, _) = False
Prelude> both (False, undefined)
False
but is this actually guaranteed by the standard? Unlike with the order of clauses, the order of evaluation of the patterns is not so clear here. Can I actually be sure that matching (True,False)
will be aborted as soon as (False,_)
is determined, before the snd element is evaluated at all?
Yes, it is guaranteed that evaluating the expression
both (False, undefined)
will not diverge since matching on data constructors is guaranteed to match left-to-right against the components of the constructor and the pattern fails as soon as some sub-pattern fails. Since the first element of the tuple isFalse
, the pattern will fail for both(True, ...)
branches as soon as the first element fails to match.Per the Haskell 2010 Report, section 3.17.2, which gives an informal semantics of pattern matching:
Since the tuple syntax is just a special-case syntactic sugar for a data constructor, the above applies.
For a fuller treatment of pattern matching, see section 3.17.3 of the Haskell 2010 Report, which gives a formal semantics of pattern matching (specifically, figure 3.2 pertains to this question).
Another resource of interest is the paper Pattern-driven Reduction in Haskell which specifies the semantics as an interpreter (written in Haskell) of an abstract syntax representation of Haskell's concrete syntax (the function
mP
in figure 3, page 7 is relevant to the question).