The problems in this assignment exercise high- and low-level functional programming concepts, including the use of functions as both arguments and return values from other functions. The last problem is an introduction to the Unicalc unit calculator application of Rex. It will be finished in Assignment 3.
You are asked to construct several function definitions in rex and test them. You should submit your rex functions in a single file named hw2.rex. When you use the cs60submit program, be sure to indicate that your rex submission is assignment number 2.
As in assignment 1, commenting your functions and your file are important. The grading of this assignment is similar to assignment 1. As you write functions to solve these problems, however, it is a good idea (and very much the spirit of rex and functional programming) to try to devise programs as elegant and concise as possible.
For an example of a thoroughly commented function, look at the file
insert.rex in the directory /cs/cs60/as/a2.
You will want to have read to Chapter 3 (rewrite rules are formally presented in Chapter 4, however) You may also want to experiment with functions returning functions and anonymous functions in rex.
Test cases for each of these problems appear in the directory
/cs/cs60/as/a2 . The names of the test-case files
are Test#.in, where # is 1 - 10.
To test a particular function that has been written in the file
hw2.rex, the following command will work:
% rex hw2.rex < /cs/cs60/as/a2/Test1.inwhere Test1.in can be replaced wih any of the test files.
rex > fahrToCel([212,32,-40]);
[100,0,-40]
The conversion of individual temperatures is C = (F-32)*(5/9.0).
In principle, this function is not different than add42List. In this
case, however, use an anonymous function as a first argument to map.
rex > erdos(42);
21
rex > erdos(109);
328
// Here I'm using the erdos function from the example above. // since the first argument is 1, the desired result is erdos(3), // which is 10. rex > iterate(1, erdos, 3); 10 // Hey, now I'm iterating twice and computing erdos(erdos(3)) rex > iterate(2, erdos, 3); 5 // And this is finding erdos(erdos(erdos(3))) rex > iterate(3, erdos, 3); 16 // Iterating the add1 function twice is equivalent to adding 2. rex > iterate(2, add1, 9); 11
erdos(erdos(erdos(3))) = 16.Continuing in this way,
erdos(erdos(erdos(erdos(erdos(erdos(erdos(3))))))) = 1with erdos iterated 7 times. Thus, collapse([3]) == [7]. Further examples of collapse in action include
rex > collapse([3, 10, 5, 16]); [7, 6, 5, 4] rex > collapse([129, 55, 85]); [121, 112, 9]Will every positive integer collapse to 1? No one knows, though many mathematicians have worked on it. The mathematician Paul Erdos actually felt that "mathematics is not yet ready for such problems" as this, known as the "3x+1" problem. Check out the site http://www.paulerdos.com/0.html for more on Paul Erdos.
// Include the file with the scoring tables
rex > sys(in,"/cs/cs60/as/a2/letterScoring.rex");
// Let scrabbleScorer be bound to the function created by
// createScorer in this case.
rex > scrabbleScorer = createScorer(scrabble);
1
rex > scrabbleScorer("rex");
10
// In this case the function output by createScorer is used immediately.
rex > createScorer(letterOrder)("ronaldwilsonreagan");
202
// To demonstrate, I'll first define two functions called foo and goo.
rex > foo(X) => 2*X + 1;
foo
rex > goo(X) => 3*X - 2;
goo
// Now, envelope(foo, goo) returns a function and here we let moo
// represent that function.
rex > moo = envelope(foo, goo);
1
// Now, let's evaluate the function moo with input of 5.
rex > moo(5);
13
[ rootValue, leftSubtree, rightSubtree ]. The
rootValue will always be an integer, and the left and right
subtrees are binary search trees. Write the function delete(X,
T) that takes a value X and a list T representing a
binary search tree and returns a binary search tree with all of the elements
of T except with X removed. You can assume that
X is definitely in the tree T. For example, the list
[10, [3, [], []], [42, [20, [], []], [60, [], []] ] ]represents the tree

rex > mytree = [10, [3, [], []], [42, [20, [], []], [60, [], []] ] ]; 1 rex > delete(10, mytree); [20, [3, [], []], [42, [], [60, [], []]]]
The last three problems are related to the "Unicalc" unit-conversion application.
The Unicalc application converts quantities expressed in one type of unit to those of another. The end result (not this week's assignment) will be able to do conversions like the following:
rex > convert( [1, ["mile"], ["hour"]], [1, ["meter"], ["second"]], db);
multiply by 0.447032 or divide by 2.23698
Unicalc works on multiplicative conversions only, so it does not
perform conversions such as Fahrenheit to Celsius.
Functional programming provides a natural way to implement the
kernel of Unicalc. In this assignment, we walk through some of the data
representations and issues, and ask you to write the first half of the code
in rex. Here are the key representations used in Unicalc:
[1.0, ["mile"], ["hour"] ] represents 1 mile per hour
[2.5, ["meter"], ["second", "second"] ] represents 1 meter per second^2
[60.0, [ ], ["second"] ] represents 60 hertz
[3.14, [ ], [ ] ] represents about pi radians
To summarize, a Quantity List is a list of three elements: the
first is the quantity (floating point), the second is a list of
units in the numerator, and the third is the list of units in the
denominator.
Note You can assume (and need to ensure) that the lists of
units (numerator and denominator) are maintained in alphabetical order.
db =
[
["foot", [12.0, ["inch"], []]],
["mile", [5280.0, ["foot"], []]],
["coulomb", [1.0, ["ampere", "second"], []]],
];
Each line in the database is a list of two elements -- the first element is a string
that names some unit and the second element is a Quantity List that is
equivalent to that named unit.
Not every unit is defined in terms of others in the database. Some are intentionally left undefined. We'll call the latter basic units. In the above example, inch, ampere, and second are basic units. A database does not need to contain conversions for everything to everything; that would tend to make it very large and maintenance would be error-prone. Instead, all conversions done by Unicalc are derived from basic ones in the database.
Some example uses of simplify include
rex > simplify([3, ["kg", "meter", "second", "second"],
["kg", "kg", "second"]]);
[3, ["meter", "second"], ["kg"]]
rex > simplify([3.14, ["meter", "second"],
["meter", "second", "second"]]);
[3.14, [], ["second"]]
rex > multiply([2.0, ["kg"], ["second"]],
[3.0, ["meter"], ["second"]]);
[6.0, ["kg", "meter"], ["second", "second"]]
rex > divide([12.5, ["meter"], ["second"]],
[0.5, ["meter"], []]);
[25.0, [], ["second"]]
(Hint: don't rewrite simplify!)
db =
[
["foot", [12., ["inch"], []]],
["mile", [5280., ["foot"], []]],
["inch", [0.0253995, ["meter"], []]],
["hour", [60., ["minute"], []]],
["minute", [60., ["second"], []]],
["mph", [1., ["mile"], ["hour"]]],
["coulomb", [1, ["ampere", "second"], []]],
["joule", [1, ["kg", "meter", "meter"],
["second", "second"]]],
["ohm", [1, ["volt"], ["ampere"]]],
["volt", [1, ["joule"], ["coulomb"]]],
["watt", [1, ["joule"], ["second"]]]
];
which happens to be the current contents of /cs/cs60/as/a2/unicalc_mini_db.rex (although this may change).
(The empty lists at the end of the first few lines above represent the denominators of the RHS. These can be seen as 1, or multiplicative identity, for the type of symbolic multiplication we use.)
If this were the entire database, we note that "meter" and "second" are both basic quantities, since they are not the LHS of any definition.
Write a rex function conv_unit that takes a string representing a unit and the database association list as arguments. If the unit is defined in the database, it returns that unit's equivalent quantity list, otherwise it returns a standard quantity list representing the unit: [1.0, [unitString], []]. For example, if db is the database consisting of the list of the pairs above, then:
rex > conv_unit("hour", db);
[60, [minute], [] ]
rex > conv_unit("meter", db);
[1, [meter], [] ]
This function would allow a more efficient solution to problem number 11 on the previous assignment, as there are at most 140 different three-letter substrings formable from seven characters. (You do not have to redo that problem!)
Just as the order of the letters inside the sublists do not matter, neither does the order of the sublists themselves within the output. For instance,
rex > subsets(2,"abcd");
[ [a, b], [a, c], [a, d], [b, c], [b, d], [c, d] ]
rex > subsets(2,"aacd")
[ [a, a], [a, c], [a, d], [c, d] ]
rex > subsets(2,"aaad")
[ [a, a], [a, d] ]
rex > subsets(5,"aacd")
[ ]