I’ve created a function in which I can use (as far as I know) case expressions or guards.
foo a b c = case a of 1 -> [...]
2 -> [...]
3 -> [...]
[...]
otherwise -> error "..."
or
foo a b c | a == 1 = [...]
| a == 2 = [...]
| a == 3 = [...]
| [...]
| otherwise = error "..."
So, the question is: which of those 2 (case or guards) are “better” coding? Are both basically the same?
In computer programming, a guard is a boolean expression that must evaluate to true if the program execution is to continue in the branch in question.
Guards are a way to augment pattern matching with more complex checks. They are allowed in a predefined set of constructs where pattern matching is allowed. Not all expressions are allowed in guard clauses, but only a handful of them.
What Are Guard Clauses? A guard clause is simply a single piece of conditional logic at the beginning of a function which will return from the function early if a certain condition is met.
The first one is considered better style, for 2 reasons.
First of all: Many people would say that it looks better, since you don't have to type out all of the ==
. This is a very subjective reason, of course. Also, you would normally not even introduce a new case statement, but just match the arguments in the function argument list like so:
foo 1 b c = ... -- etc
...
foo _ b c = ... -- for the "otherwise" part
This makes the code even more compact and readable, which many people like.
Secondly, there actually is a semantic difference. Imagine that you have a data type like this:
data Cake = Apple | Cheese | Cream
If you use the first method, you match against the constructors in the case..of
expression:
case a of
Apple -> "fruit"
_ -> "not fruit"
However, if you try to do a guarded expression of some sort, like this:
| a == Apple = "fruit"
| otherwise = "not fruit"
... it won't actually work, because the Cake
type doesn't have an Eq
instance, so you can't use ==
to compare two values. Introducing an Eq
instance (with deriving (Eq)
after the data definition) is not always wanted, so not having to do it in this case might be significant.
When a guard can be rewritten as a (guardless) case-statement on one of the parameters, it's not actual necessary. I.e. you can just write it as:
foo 1 b c = [...]
foo 2 b c = [...]
foo 3 b c = [...]
[...]
Which is the preferred way to write it. You'd use guards when the condition you want can't be expressed as a pattern. And you'd use a case-statement when you need to match on something other than one of the parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With