The evaluation of the arguments of a function is first determined by the patterns used to bind the arguments.
If you have
short :: Val -> Exp -> Error Val
short val ex
| condition on val only = something
| other condition on val only = somethingElse
| condition involving ex too = thirdPossibility
| otherwise = whatever
no evaluation takes place on binding the arguments, since the patterns are irrefutable variable patterns, val
is - partially or maybe completely - evaluated to determine the outcome of the first guard. If that evaluates to True
, exp
is only evaluated if it is used in something
and its evaluation is necessary to evaluate something
. Only if the first two conditions evaluate to False
, ex
is evaluated to determine the value of the third guard (and maybe not even then).
If you can shortcut based on the constructor of val
, you can use a refutable pattern for val
and let ex
be a variable pattern (just an identifier), you get the same short-circuiting as for (&&)
etc.
short (Val foo) ex = Okay (foo bar ex)
short (Lav oof) _ = Okay oof
short val ex
| isGood val = oomph
| isBad ex = error "Didn't expect that"
| otherwise = undefined
If you don't use the Exp
argument on the right hand side, you don't even need to give it a name, the wildcard _
says "here is an argument that shall be ignored".
For your desired behaviour of
short :: Val -> Exp -> Error Val
short (Partial (&&) False) = False
that as such doesn't work because False
is a Bool
and not a Val
, you can use
short (Partial OR (VB False)) _ = S False
with a hypothetical constructor OR
of Oper
. (You can use (&&)
there, but that is a variable pattern matching anything.) That pattern doesn't even bind the Exp
argument, so unless its evaluation has been forced by previous equations for short
, it remains unevaluated.