Case expressions are useful for conditionals that have two or more branches. Some other languages call this kind of expression a “switch”. As mentioned on the previous page, pattern guards can also be used to a similar effect.
This program uses the
time package for handling time conversions.
The branches are introduced once by
case...of. Haskell doesn’t typically use curly braces, but the
of is necessary and the indentation matters.
The values on the left side of the
-> arrows are the cases of the type that the expression in
case <exp> of evaluates to. The
< function returns a Boolean, so this an alternate to
if expressions but with explicit matching.
= timeNow now case todHour (localTimeOfDay (zonedTimeToLocalTime now)) < 12 of True -> putStrLn "It's before noon" False -> putStrLn "It's after noon"
case expressions can be used to match on the values of a custom datatype. Here is a custom type representing three mutually exclusive service plans.
billAmount function associates a
ServicePlan value to a numeric value.
data ServicePlan = Free | Monthly | Annual = billAmount plan case plan of Free -> 0 Monthly -> 5 Annual -> billAmount Monthly * 12
Some types have more values than you want to match on manually, and maybe some of the possible inputs are irrelevant to your needs. An underscore in the final case is a catchall that will match against any value.
= writeNumber i case i of 1 -> "one" 2 -> "two" 3 -> "three" -> "unknown number" _
You can use those functions in a
main program by declaring some variables and applying the functions to them within the
do-block. This is what
runhaskell will run (see below).
= main do <- getZonedTime now timeNow now let plan = Free putStrLn ("Customer owes " ++ show (billAmount plan) ++ " dollars.") let i = 2 putStrLn ("Write " ++ show i ++ " as " ++ (writeNumber i))
Let’s use the REPL to check our work. Passing the filename you want to load into the GHCi session ensures that all the things you need are in scope at the start of your session.
$ ghci branching.hs
GHCi can give lots of information about programs. This session demonstrates applying single functions to appropriate arguments.
λ> billAmount Monthly 5 λ> billAmount Annual 60 λ> writeNumber 6 "unknown number"
If you try applying
billAmount to a number, or
writeNumber to a Boolean, GHCi will become annoyed. Displayed here are the first lines of the error messages you’d receive for these examples. Both of them are conveying the information that neither
ServicePlan values nor
Bool values are numbers, so they cannot be used interchangeably with numbers.
λ> billAmount 5 <interactive>:3:12: error: • Could not deduce (Num ServicePlan) arising from the literal ‘5’ λ> writeNumber True <interactive>:4:1: error: • No instance for (Num Bool) arising from a use of ‘writeNumber’
>>= function can be thought of as a means of passing the output of the first function,
getZonedTime, to a second function. The first example only prints the output of
getZonedTime. The second example passes the output of
getZonedTime to our
λ> getZonedTime >>= print 2019-07-30 14:04:19.224690712 MDT λ> getZonedTime >>= timeNow It's after noon
When you want to quit GHCi, use
λ> :quit Leaving GHCi.
You can use
runhaskell to run the
main program. Note that outputs that depend on the current time may be different when you run the program locally.
$ runhaskell branching.hs It's after noon Customer owes 0 dollars.Write 2 as two