- Use try.purescript.org to test out the code examples in this book.
- Whenever the example code starts with
module Main where, make sure to clear out the code editor on try.purescript.org before pasting new code in. This will help to avoid unncessary errors
It's time to introduce a very important concept; we'll call it decision making. Up to this point,
we've worked with various types of input, but we haven't really done anything interesting with that
data. Our programs run straight through from start to finish with the same behavior regardless of
the data it gets. What we really want is to have a program that does different things based on what
we give it!
For example, we might write a program that greets the user differently based on their age, saying "Hello child!" to ages below 18 and "How do you do?" to those above. Another example might be a prize received for acheiving a certain grade in school. Perhaps C grades and lower earn pencils, B grades earns you a candy, and A grades will get you a hamburger! We can write programs that do the above using
case statements, let's look at some examples.
To start, we'll stay simple and use our
CoolType defined in the previous chapter. Using this type,
we'll output a different string based on which
CoolType value we're using.
module Main where import Prelude import Debug data CoolType = Cool | VeryCool | SuperCool -- | Returns a cool string message based on the `CoolType` value getCoolMessage :: CoolType -> String getCoolMessage coolVar = case coolVar of Cool -> spy "msg" "Cool..." VeryCool -> spy "msg" "That seems... very cool..!" SuperCool -> spy "msg" "You couldn't be cooler" message1 :: String message1 = getCoolMessage VeryCool message2 :: String message2 = getCoolMessage SuperCool
If you check the developer console, you should see the following output:
msg: That seems... very cool..! msg: You couldn't be cooler
The above example shows nearly everything there is to see regarding the basics of case statements.
Your intuition may be enough to understand what's happening, but before we break down the example
further, let's look at the
case statement a little more closely.
The syntax for our case statement is as follows
case value of case1 -> response1 case2 -> response2 ...
The first part is
case value of. We can put anything with a value between the
case and the
keywords (taking the place of the word
value above), for example:
- A top-level variable
- A function parameter
- An actual function call which returns a value
wherebindings which yeild a value.
module Main where import Prelude data Decision = This | That -- 1. Top-level variable someDecision :: Decision someDecision = This topLevelCase :: Int topLevelCase = case someDecision of This -> 10 That -> 20 -- 2. A function parameter caseFunction :: Decision -> String caseFunction decision = case decision of This -> "This thing" That -> "That thing" -- 3. A function call -- We ignore the `num` parameter and just return a `That` someFunction :: Int -> Decision someFunction num = That functionCallCase :: Boolean functionCallCase = case someFunction 20 of This -> false That -> true -- 4. Let/Where bindings in a case letCase :: String letCase = let letVar = That in case letVar of This -> "Hello" That -> "Goodbye" whereCase :: Int whereCase = case whereVar of This -> 20 That -> 100 where whereVar = This
The next part to turn our attention to is:
case1 -> response1 case2 -> response2
That is: some value, followed by an
-> followed by some sort of response value.
What are the values
case2, etc? These correspond to the values associated with our type;
we'll have as many cases as we do values for that type.
module Main where import Prelude -- -- 1. A single value type -- data Boring = Boo -- There's only one case value to work with here: `Boo`. ex1 :: Boring -> Boolean ex1 var = case var of Boo -> true -- -- 2. A type with 2 valid values -- data Decision = This | That -- We have two valid values for the Decision type, so we have two cases to deal with ex2 :: Decision -> Boolean ex2 decision = case decision of This -> true That -> false -- -- 3. A Type with three valid values data CoolType = Cool | VeryCool | SuperCool -- Our Original CoolType has 3 valid values, so we have three cases to deal with now ex3 :: CoolType -> Int ex3 coolVal = case coolVal of Cool -> 10 VeryCool -> 90 SuperCool -> 9001 -- It's over 9000!
Ah so now that we've been through a basic run down of
case statements, we return to our original
module Main where import Prelude import Debug data CoolType = Cool | VeryCool | SuperCool -- | Returns a cool string message based on the `CoolType` value getCoolMessage :: CoolType -> String getCoolMessage coolVar = case coolVar of Cool -> spy "msg" "Cool..." VeryCool -> spy "msg" "That seems... very cool..!" SuperCool -> spy "msg" "You couldn't be cooler"
Hopefully reading this makes a lot more sense now. We check the three possible values we could
encounter for the
CoolType type, and use
spy to output the appropriate message to the console.
We can also use
case statements on the primitive types.
module Main where import Prelude import Debug -- | Write to the console a string and return it based on a Boolean (true/false) areYouCool :: Boolean -> String areYouCool bool = case bool of true -> spy "msg" "I knew you were!" false -> spy "msg" "Aw cmon, you're cooler than you think!"
It's also possible to use
case statements on bigger types, like
String, but we aren't
equipped to deal with that just yet.
Case statements rely on Pattern Matching to inspect the
values, and we've only used the simplest of pattern matches here. In the next chapter, we'll go
into a deeper exploration of Pattern Matching to learn how to handle a couple of the more
complicated and common scenarios.
Finally, one last thing to take note of: Because
case statements yield a value just like a
variable or a function, all the different response values of our
case statement must be the same
type. If you try to use a different type in each response, you'll be met with an error.
module Main where import Prelude -- This function won't compile badCaseFunc :: Boolean -> String badCaseFunc bool = case bool of true -> "Hello!" false -> 54
The above is wrong because the
case statement tries to return a
String in the
true case but an
Int in the
false case (Also because badCaseFunc should return a
String in general).
case statements to inspect the values of a type, allowing us to react in different ways to
the different possibilites.
The syntax of a case statement takes the general form
case value of case1 -> response1 case2 -> response2 ...
valueis some value (like a variable)
- Each case covers a different possible value for
- Each response following the
->gives us a way act differently based on each case.
- And each response must be of the same type
Here's an example of a simple
module Main where import Prelude data Greeting = Hello | Hi | Yo responseToGreeting :: Greeting -> String responseToGreeting greeting = case greeting of Hello -> "Hello to you" Hi -> "Hey!" Yo -> "Yo yo yo!"
1. Using the following type:
data LetterGrade = A | B | C | D | F
Write a function called
prize which outputs a string to the console telling the user what prize
they have won for their efforts. Create 2 variables and assign them the result of our
function so you can see it work in the console.
2. Using the following type:
data BetterBool = Yes | No
Create a function called
upgradeBool which takes a
Boolean and turns it into a
Next, create a function called
downgradeBool which takes a
BetterBool and turns it back into a
module Main where import Prelude import Debug data LetterGrade = A | B | C | D | F prize :: LetterGrade -> String prize grade = case grade of A -> spy "A Prize" "In N Out" B -> spy "B Prize" "Little Ceasars" C -> spy "C Prize" "2oz cup frozen yogurt" D -> spy "D Prize" "Jolly Rancher" F -> spy "F Prize" "One potato chip" reward1 :: String reward1 = prize B reward2 :: String reward2 = prize F
module Main where import Prelude data BetterBool = Yes | No upgradeBool :: Boolean -> BetterBool upgradeBool bool = case bool of true -> Yes false -> No downgradeBool :: BetterBool -> Boolean downgradeBool better = case better of Yes -> true No -> false