Topic 2: Making Decisions 1
Recommended Exercises and Readings From Haskell: The craft of functional programming (3 rd Ed.) Exercises: 3.1, 3.5, 3.8, 3.9, 3.10, 3.11, 3.13, 3.14, 3.16, 3.17, 3.18, 3.19, 3.20, 3.22, 3.23 and 3.24 Readings: Chapter 3 2
Making Decisions Most Interesting functions perform different tasks for different parameter values What mechanisms exist to make decisions? 3
Making Decisions A quick look at if and if else if (i < 0) if (i < 5) cout << "A" << endl; else cout << "B" << endl; What does this code display for i == 0 i == 3 i == 6? 4
Making Decisions A closer look at switch case case somechar of 'a', 'e', 'i', 'o', 'u': writeln('vowel'); 'y': writeln( Vowel or consonant'); else writeln('consonant'); end; switch (somechar) { case 'a': case 'e': case 'i': case 'o': case 'u': cout << "Vowel" << endl; case 'y': cout << "Vowel or consonant" << endl; default: cout << "Consonant" << endl; } given ($somechar) { when (['a', 'e', 'i', 'o', 'u']) { say 'Vowel'; } when ('y') { say 'Vowel or consonant'; } default { say 'Consonant'; } } switch (somechar) { case 'a': case 'e': case 'i': case 'o': case 'u': Console.WriteLine("Vowel"); case 'y': Console.WriteLine("Vowel or consonant"); default: Console.WriteLine("Consonant"); } 5
Making Decisions A closer look at switch case Provided by many languages But details vary Default is to fall through: C, C++, Java break prevents fall through Cannot fall through: Pascal, C# Default is not to fall through: Perl continue permits it Not included: Python Can fake it with a dictionary Advantages of switch case compared to if elif else? Disadvantages? 6
An Elegant Use of Fall Through // // Determine the day within the year // (New Year's Day is day 1) // int get_day_of_year(int day, int month, int year) { int day_of_year = day; switch (month) { case 12: day_of_year += 30; case 11: day_of_year += 31; case 10: day_of_year += 30; case 9: day_of_year += 31; case 8: day_of_year += 31; case 7: day_of_year += 30; case 6: day_of_year += 31; case 5: day_of_year += 30; case 4: day_of_year += 31; case 3: if (is_leap_year(year)) day_of_year += 29; else day_of_year += 28; case 2: day_of_year += 31; } return day_of_year; } 7
Making Decisions A closer look at inline if / conditional expressions Called by many different names Ternary if, ternary conditional, ternary operator, conditional operator, inline if, conditional expression, Allows a program to make a decision inside an expression System.out.println(x + " is an " + (x % 2 == 0? "even" : "odd") + " integer"); print("the value" + ("s are" if len(data) > 1 else " is"), data) Can be used as an lvalue in C++ x = 0; y = 0; cout << "Before: x is " << x << ", y is " << y << endl; (change_x == true? x : y) = 1; cout << "After: x is " << x << ", y is " << y << endl; 8
Making Decisions Decision Making Structures in Haskell Pattern matching Guards if then else case 9
Pattern Matching Pattern matching permits multiple definitions for the same function Patterns describe combinations of values that can be passed to the function Each pattern is checked in sequence The first matching pattern executes 10
Pattern Matching Convert the following truth table into a Haskell Function: a b result False False True False True True True False False True True True 11
Pattern Matching Patterns can include a mixture of formal parameter variables and values Example: Construct a function, named mydiv, which divides a floating point numerator by a floating point denominator. The function should report an error if the denominator is 0. 12
Pattern Matching Works well for a small number of special cases Unable to handle two large collections of values like all positive integers and all negative integers Pattern order matters More specific patterns must be listed first Patterns can be applied to any data type By convention, _ is used for formal parameter variables that are not used in the function body 13
Guards Guards Permit a function s behavior to vary based on arbitrary expressions Often contain relational operators Less than Less than or equal Greater than Greater than or equal Equal Not equal 14
Guards Example: Construct a comparison function that takes one integer parameter, x. It will return 1 when x is less than 0 0 when x is equal to 0 1 when x is greater than 0 15
Combining Pattern Matching and Guards Pattern matching and guards can be combined Guards apply to the pattern that immediately precede them If none of the guards for a pattern evaluate to true, Haskell will move on to the next pattern Example: An alternative implementation of the comparison function 16
Guards Guards are evaluated in order Only the statement associated with the first guard that evaluates to true is executed Example: Convert a character from lowercase to uppercase Other characters should be returned unchanged 17
if then else Can be used within another expression Analogous to Java and C++ ternary conditional, or Python s conditional expression Example: Write a function that takes a character as its only parameter. The function will return a string containing a message that indicates whether or not the character is uppercase. For example A is an uppercase letter or b is not an uppercase letter. 18
case Pattern matching on an arbitrary expression Example: Write a function that reports whether or not a character is a vowel Should work for both upper and lowercase letters Don t want to list both the uppercase and lowercase vowels Y is sometimes a vowel 19
Summary Most languages provide multiple decision making constructs Imperative and object oriented languages if, if else, if elif else Switch / case Conditional operator / conditional expressions Haskell Pattern matching Guards if then else case 20