Examples of functional pseudo-code

Nic McPhee
University of Minnesota, Morris


Here are examples of using a functional pseudo-code to express some of the algorithms in Chapter 2 of An invitation to computer science by Schneider and Gersting.

In all these examples I assume that the pseudo-code in the text has been modified to return values instead of printing them. If that's the only change I've made to the pseudo-code, then I've not repeated it here. If I've made more substantial changes to the text's pseudo-code, then I've included the algorithm in both the book's pseudo-code and this functional pseudo-code.


[Euclid's GCD algorithm] [Factorial] [Average miles per gallon (version 1)] [Average miles per gallon (version 2)] [Sequential search] [Find largest] [Pattern matching]


Euclid's GCD algorithm (Chapter 1, Exercise 7)

I've rewritten their GCD algorithm to use a while loop instead of that annoying GOTO in Step 3.

  1. Get 2 positive integers as input. Call the larger I and the smaller J.
  2. Divide I by J and call the remainder R.
  3. While R is not 0
    1. Reset I to the value of J
    2. Reset J to the value of R
    3. Reset R to the remainder of dividing the new I by the new J.
  4. End of While
  5. Return J.

In the functional version I'll assume the first argument (i) is greater than the second (j).

    gcd i j
        = j, if r = 0
        = gcd j r, if r != 0
          where
          r = i mod j


Factorial

The example of factorials doesn't appear in the book, but they are defined at the beginning of Lab 3, and are sufficiently similar to GCDs that I thought I'd include them.

First, using the book's pseudo-code:

  1. Input n
  2. Set p to 1
  3. While n is not equal to 0
    1. Reset p to p * n
    2. Reset n to n - 1
  4. End of While
  5. Return p

Then using the functional pseudo-code:

    factorial n
        = 1, if n = 0
        = n * factorial (n-1), otherwise


Average miles per gallon (Figure 2.3, page 30)

    average_mpg gallons_used starting_mileage ending_mileage
        = avg
          where
          distance_driven = ending_mileage - starting_mileage
          avg = distance_driven / gallons_used


Average miles per gallon, version 2 (Figure 2.4, page 32)

One could make a strong argument that one shouldn't perform the "good mileage" check in the same routine that computes the mileage, as it makes this routine much less useful on other contexts. Arguably this algorithm should simply compute the average miles per gallon and return the result, leaving it to another algorithm (or individual) to decide what's good or bad. Similarly, the third version of this algorithm (Figure 2.5, page 34) suffers from over complication.

Given that caveat, I'll go ahead and do version two just because it illustrates conditionals again. Just remember that this isn't a very good way to organize your problem solving.

    average_mpg gallons_used starting_mileage ending_mileage
        = (avg, "You're getting good gas mileage"), if avg > 25
        = (avg, "You're not getting good gas mileage"), otherwise
          where
          distance_driven = ending_mileage - starting_mileage
          avg = distance_driven / gallons_used


Sequential search (Figure 2.9, page 40)

There are two distinct approaches to this problem depending on how we want to represent the inputs, and I'll provide both versions. In the first version we'll have two separate inputs: The list of names, and the list of telephone numbers. In the second version there will be a single input, namely a list of pairs of names and numbers. Which one of the two you'd prefer would depend largely on the way in which your data is stored when you call this algorithm. I personally prefer the second (list of pairs) version, because you can't accidentally get the two lists out of synch, but if what you've got is two separate lists, the first one might make more sense.

First, the version with two separate lists:

    sequential_search name [] [] = error "Name not found"
    sequential_search name (n:ns) (t:ts)
        = t, if name = n
        = sequential_search name ns ts, otherwise

Then the version with a single list of pairs:

    sequential_search name [] = error "Name not found"
    sequential_search name ((n, t):pairs)
        = t, if name = n
        sequential_search name pairs, otherwise


Find largest (Figure 2.10, page 45)

    find_largest [] = error "Empty list not allowed"
    find_largest (x:xs) = do_find_largest x xs
    
    do_find_largest largest_so_far [] = largest_so_far
    do_find_largest largest_so_far (x:xs)
        = do_find_largest largest_so_far xs,   if largest_so_far > x
        = do_find_largest x xs,                otherwise


Pattern matching (Figure 2.12, page 51)

    match [] pattern = False
    match (t:ts) pattern
        = (prefix_match (t:ts) pattern) OR (match ts pattern)
    
    prefix_match text []    = True
    prefix_match [] pattern = False
    prefix_match (t:ts) (p:ps)
        = prefix_match ts ps,   if t = p
        = False,                otherwise

The views and opinions expressed in this page are strictly those of the page author. The contents of this page have not been reviewed or approved by the University of Minnesota.