A Simple Example of Using Functional Programming
Author |
Message |
wtd
|
Posted: Wed Nov 02, 2005 2:56 pm Post subject: A Simple Example of Using Functional Programming |
|
|
At some point in our educational career, we've all had to write some trivial program where we do something with a set of grades.
Well, here's a problem. You have two sets of grades for a student. One represents scores in math, and the other science. Being a nice teacher, you're going to throw out a bunch of those scores. You want to keep any scores where the scores in corresponding locations in the lists average out to a passing grade, which we'll set at an arbitrary 75%.
First off we need two lists of grades.
code: | # let science_grades = [56; 78; 98; 47]
let math_grades = [100; 67; 88; 65];;
val science_grades : int list = [56; 78; 98; 47]
val math_grades : int list = [100; 67; 88; 65] |
Now, how to we proceed from here?
We need to compare corresponding grades, but we can't iterate over two lists at once. Or can we?
The combine function in the List module will take two lists and create a list of tuples.
code: | # let combined_grades = List.combine science_grades math_grades;;
val combined_grades : (int * int) list =
[(56, 100); (78, 67); (98, 88); (47, 65)] |
Now, we need a function which can operate on a tuple of two grades and determine if they're acceptable to keep.
code: | # let acceptable_grades (s, m) = (s + m) / 2 >= 75;;
val acceptable_grades : int * int -> bool = <fun> |
Now we can filter our combined grades using the filter function from the List module.
code: | # let combined_grades' = List.filter acceptable_grades combined_grades;;
val combined_grades' : (int * int) list = [(56, 100); (98, 88)] |
Now,we need only get back to what we had before. The split function, again from the List module will do quite nicely. It will give us a tuple of two lists. We can pattern match against this in a let binding to let us name the two lists easily.
code: | # let science_grades', math_grades' = List.split combined_grades';;
val science_grades' : int list = [56; 98]
val math_grades' : int list = [100; 88] |
Putting this all in one place, and using local bindings, we get:
code: | let science_grades = [56; 78; 98; 47]
let math_grades = [100; 67; 88; 65]
let science_grades', math_grades' =
let combined_grades = List.combine science_grades math_grades
and acceptable_grades (s, m) = (s + m) / 2 >= 65
in
List.split (List.filter acceptable_grades combined_grades) |
Let's look at something like this in Java.
Java: | public class Grades
{
public static void main (String[] args )
{
int[] scienceGrades = new int[] {56, 78, 98, 47}
int[] mathGrades = new int[] {100, 67, 88, 65}
int[] filteredScienceGrades = new int[4];
int[] filteredMathGrades = new int[4];
int numberOfFilteredGrades = 0;
for (int gradeIndex = 0; gradeIndex < scienceGrades. length; gradeIndex++ )
{
int currentScienceGrade = scienceGrades [gradeIndex ];
int currentMathGrade = mathGrades [gradeIndex ];
if ((currentScienceGrade + currentMathGrade ) / 2 >= 75)
{
filteredScienceGrades [numberOfFilteredGrades ] = currentScienceGrade;
filteredMathGrades [numberOfFilteredGrades ] = currentMathGrade;
numberOfFilteredGrades++;
}
}
}
} |
Thought this is not to argue that Oobjective-Caml is superior to Java, it does demonstrate that functional programming languages make manipulation of lists and other aggregate data structures remarkably convenient, compared to more "mainstream" languages.
A compromise might be something like Ruby.
code: | science_grades = [56, 78, 98, 47]
math_grades = [100, 67, 88, 65]
combined_grades = [science_grades, math_grades].transpose
filtered_combined_grades = combined_grades.select { |s, m| (s + m) / 2 >= 75 }
filtered_science_grades, filtered_math_grades = filtered_combined_grades.transpose |
|
|
|
|
|
|
Sponsor Sponsor
|
|
|
|
|