matt
matt

Reputation: 2089

Haskell and multiple conditions

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

Answers (2)

Kwarrtz
Kwarrtz

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

user1002430
user1002430

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

Related Questions