[Appendix A] A.7 Chapter 8, Functions
Author: Randal L. Schwartz, Erik Olson & Tom Christiansen
Date: 1999-07-02T01:37:33Z

#

| Appendix A Exercise Answers |

## A.7 Chapter 8, Functions

1. Here's one way to do it:

       sub card {
         my %card_map;
         @card_map{1..9} = qw(
           one two three four five six seven eight nine
         );

         my($num) = @_;
         if ($card_map{$num}) {
           $card_map{$num}; # return value
         } else {
           $num; # return value
         }
       }
       # driver routine:
       while (<>) {
         chomp;
         print "card of $_ is ", &card($_), "\n";
       }

   The `&card` subroutine (so named because it returns a cardinal name for a given value) begins by initializing a constant hash called `%card_map`. This array has values such that `$card_map{6}` is `six`; consequently, the mapping is easy.

   The `if` statement determines if the value is in range by looking the number up in the hash - if there's a corresponding hash element, the test is true, so that array element is returned. If there's no corresponding element (such as when `$num` is `11` or `-4`), the value returned from the hash lookup is `undef`, so the `else`-branch of the `if` statement is executed, returning the original number. You can also replace that entire `if` statement with the single expression:

         $card_map{$num} || $num;

   If the value on the left of the `||` is true, it's the value for the entire expression, which then gets returned. If it's false (such as when `$num` is out of range), the right side of the `||` operator is evaluated, returning `$num` as the return value.

   The driver routine takes successive lines, `chomp`ing off their newlines, and hands them one at a time to the `&card` routine, printing the result.

2. Here's one way to do it:

       sub card { ...; } # from previous problem
       print "Enter first number: ";
       chomp($first = <STDIN>);
       print "Enter second number: ";
       chomp($second = <STDIN>);
       $message = &card($first) . " plus " .
         &card($second) . " equals " .
         &card($first+$second) . ".\n";
       print "\u$message";

   The first two `print` statements prompt for two numbers, with the immediately following statements reading the values into `$first` and `$second`.

   A string called `$message` is then built up by calling `&card` three times, once for each value, and once for the sum.

   After the message is constructed, its first character is uppercased by the case-shifting backslash operator `\u`. The message is then printed.

3. Here's one way to do it:

       sub card {
         my %card_map;
         @card_map{0..9} = qw(
           zero one two three four five six seven eight nine
         );

         my($num) = @_;
         my($negative);
         if ($num < 0) {
           $negative = "negative ";
           $num = - $num;
         }
         if ($card_map{$num}) {
           $negative . $card_map{$num}; # return value
         } else {
           $negative . $num; # return value
         }
       }

   Here, we've given the `%card_map` array a name for 0.

   The first `if` statement inverts the sign of `$num`, and sets `$negative` to the word negative, if the number is found to be less than 0. After this `if` statement, the value of `$num` is always non-negative, but we will have an appropriate prefix string in `$negative`.

   The second `if` statement determines if the (now positive) `$num` is within the hash. If so, the resulting hash value is appended to the prefix within `$negative`, and returned. If not, the value within `$negative` is attached to the original number.

   That last `if` statement can be replaced with the expression:

         $negative . ($card_map{$num} || $num);

A.6 Chapter 7, Regular Expressions |  | A.8 Chapter 9, Miscellaneous Control Structures