if 表達式



if <condition> then <true-value> else <false-value>


if <condition>
   then <true-value>
   else <false-value>

if <condition>


message42 :: Integer -> String
message42 n =
   if n == 42
      then "The Answer is forty two."
      else "The Answer is not forty two."



One interesting way of thinking about case expressions is seeing them as a generalization of if expressions. We could even write a clone of if as a case:

alternativeIf :: Bool -> a -> a -> a
alternativeIf cond ifTrue ifFalse =
  case cond of
    True  -> ifTrue
    False -> ifFalse

First, this checks cond for a pattern match against True. If there is a match, the whole expression will evaluate to ifTrue, otherwise it will evaluate to ifFalse (since a Bool can only be True or False there is no need for a default case). case is more general than if because the pattern matching in which case selection is based allows it to work with expressions which evaluate to values of any type. [1] In fact, the left hand side of any case branch is just a pattern, so it can also be used for binding:

describeString :: String -> String
describeString str = 
  case str of
    (x:xs) -> "The first character is: " ++ [x] ++ "; the rest of the string is: " ++ xs
    ""     -> "This is an empty string."

This expression tells you whether str is an empty string or something else. Of course, you could just do this with an if-statement (with a condition of str == []), but using a case binds variables to the head and tail of our list, which is convenient in this instance.

Equations and Case Expressions


Remember you can use multiple equations as an alternative to case expressions. The describeString function above could be written like this:

describeString :: String -> String
describeString (x:xs) = "The first character is " ++ [x] ++ "; the rest of the string is " ++ xs
describeString ""     = "This is the empty string."

Named functions and case expressions at the top level are completely interchangeable. In fact the function definition form shown here is just syntactic sugar for a case expression.

One handy thing about case expressions, and indeed about Haskell control structures in general, is that since they evaluate to values they can go inside other expressions just like an ordinary expression would. For example, this case expression evaluates to a string which is then concatenated with two other strings, all inside a single expression:

data Colour = Black | White | RGB Int Int Int

describeColour :: Colour -> String
describeColour c = 
  "This colour is "
  ++ case c of
       Black           -> "black"
       White           -> "white"
       RGB 0 0 0       -> "black"
       RGB 255 255 255 -> "white"
       _               -> "freaky, man, sort of in between"
  ++ ", yeah?"

Writing this function in an equivalent way using the multiple equations style would need a named function inside something like a let block.



As shown, if we have a top-level case expression, we can just give multiple equations for the function instead, which is often neater. Is there an analogue for if expressions? It turns out there is. We use some additional syntax known as "guards". A guard is a boolean condition, like this:

describeLetter :: Char -> String
describeLetter c
   | c >= 'a' && c <= 'z' = "Lower case"
   | c >= 'A' && c <= 'Z' = "Upper case"
   | otherwise            = "Not a letter"

Note the lack of an = before the first |. Guards are evaluated in the order they appear. That is, if you have a set up similar to the following:

f (pattern1) | predicate1 = w
             | predicate2 = x
f (pattern2) | predicate3 = y
             | predicate4 = z

Then the input to f will be pattern-matched against pattern1. If it succeeds, then predicate1 will be evaluated. If this is true, then w is returned. If not, then predicate2 is evaluated. If this is true, then x is returned. Again, if not, then we jump out of this 'branch' of f and try to pattern match against pattern2, repeating the guards procedure with predicate3 and predicate4. Unlike the else in if statements, otherwise is not mandatory. Still, if no guards match an error will be produced at runtime, so it's always a good idea to provide the 'otherwise' guard, even if it is just to handle the "But this can't happen!" case (which normally does happen anyway...).

The otherwise you saw above is actually just a normal value defined in the Standard Prelude as:

otherwise :: Bool
otherwise = True

This works because of the sequential evaluation described a couple of paragraphs back: if none of the guards previous to your 'otherwise' one are true, then your otherwise will definitely be true and so whatever is on the right-hand side gets returned. It's just nice for readability's sake.

  1. Again, this is quite different from what happens in most imperative languages, in which switch/case statements are restricted to equality tests, often only on integral primitive types.


起步  >> 變量和函數  >> 列表和元組  >> 更進一步  >> 類型基礎  >> 簡單的輸入輸出  >> 類型聲明


Haskell基礎 >> 初級Haskell >> Haskell進階 >> Monads
高級Haskell >> 類型的樂趣 >> 理論提升 >> Haskell性能

庫參考 >> 普通實務 >> 特殊任務