Reputation: 2089
If I have multiple conditions that are only slightly different, what is the best way to write a function (considering and inability to nest guards) of the form:
f | a && b && c = 1
| a && b && d = 2
| a && b && e = 3
| a && g && e = 4
etc
Imagine there are more a lot more conditions. Ideally I would like to write a nested if that would check for a then b then something else, but I have been told that this not possible in Haskell.
Also, in the example. If the first line returns falls, are the conditions a and b checked again if they not defined in a where clause?
Upvotes: 0
Views: 2627
Reputation: 2753
The problem with if statements in this case isn't that they can't be nested, its that they always have to have an else
component, which makes them very unwieldy in this case, because you have to include the fallback case in every statement. Your example in if statements would look something like this.
f = if a then
if b then
if c then 1
else if d then 2
else if c
then 3
else 5
else 5
else if g then
if e
then 4
else 5
else 5
As for your other options, that depends exactly on the situation. If a
,b
,etc. are arguments to f
, then you can pattern match on the function.
f True True True False False False False = 1
f True True False True False False False = 2
f True True False False True False False = 3
f True False False False True False True = 4
f _ _ _ _ _ _ _ = 5
However, if the variables are global, or defined in a where
clause, you would need to use a case
statement.
f =
case (a, b, c, d, e, f, g) of
(True, True, True, _, _, _, _) -> 1
(True, True, _, True, _, _, _) -> 2
(True, True, _, _, True, _, _) -> 3
(True, _, _, _, True, _, True) -> 4
_ -> 5
Realistically, though, as long as your variable names aren't too ridiculously long, your solution is probably the best mix of readability and conciseness. As for efficiency, boolean operations are so cheap, unless this function is included in some tight loop in a very intensive algorithm, I doubt you will be able to see any difference in speed between these options.
Upvotes: 2
Reputation:
I'd use a case
:
f x y z =
case (a, b, c, d, e, f, g) of
(True, True, True, _, _, _, _) -> 1
(True, True, _, True, _, _, _) -> 2
(True, True, _, _, True, _, _) -> 3
(True, _, _, _, True, _, True) -> 4
where
a = ...
b = ...
c = ...
Because these cases are not exclusive, you'd need to make sure the order and/or the coverage is such that you get your expected answers.
Upvotes: 1