Homework 3Data Types and Curried Functions |
Modified: |
Relational database operations common to the SQL language supported by Access, MySQL, Oracle and many others are based upon the standard mathematical operations on sets of union, intersection, difference and Cartesian product. Other operations specifically for maniuplating relational databases are select, project and join. For example, the standard SELECT operation serves to filter elements that meet some specified criteria. In the following exercise, we will implement a simple relational database using these set theoretic operations.
First a definition of the set data type supported in our database. The
sets are defined as lists where I is an int list, S is a string list, etc. The
Cartesian product, for example of IxS produces an (int * string) tuple
list. The naming of the data types attempts to hint at tuples definition so that
SI is a list of (string * int) tuples, the result of SxI; SIIS is a list of
((string*int)*(int*string)), the result of (SxI)x(IxS), etc. Below are basic
set definitions in ML:
| datatype set =
(* Examples *) I of int list | (* I [1,2,3] *) S of string list | (* S ["a","b","c"] *) IS of (int * string) list | (* IS [(1,"a"), (2,"b") ] *) II of (int * int) list| (* II [(1,2), (3,4), (5,6)] *) SS of (string * string) list | (* SS [("a","b"), ("c","d")] *) SI of (string * int) list | (* SI [("a",1), ("b",2)] *) SISI of ((string * int) * (string * int)) list | (* SISI [(("a",1),("b",2)), (("c",3),("d",4))] *) SIIS of ((string * int) * (int * string)) list; (* SIIS [(("a",1),(2,"b")), (("c",3),(4, "d"))] *) |
It is recommended to do Assignments 1-7 in order. Write and give output from TESTING each of the following assignments:
fun product (I s1) (I s2) = II (pairs s1 s2)
| product (S s1) (S s2) = SS (pairs s1 s2)
| product (SI s1) (IS s2) = SIIS (pairs s1 s2);
For example:
val i2 = I [5555,6666];
val s2 = S ["CHEM", "MATH"];
product i2 s2; (* IxS *)
val it = IS [(5555, "CHEM"), (5555, "MATH"), (6666, "CHEM"), (6666, "MATH")] : set
product s2 i2; (* SxI *)
val it = SI [("CHEM", 5555), ("CHEM", 6666), ("MATH", 5555), ("MATH", 6666)] : set
Complete defining the product for the remaining three set cases of IS, SI,
and SISI (I and S
are not product results).
You will need to define a pairs function that generates all
possible pairs as tuples of elements from two lists. Hint: Write a function to
distribute one element across every element of a list; dist (3, ["a","b","c"])
returns [(3, "a"), (3, "b"), (3, "c")].
Test using the following. Show result of last test.
| val i1 = I [1111,2222,3333]; val i2 = I [5555,6666]; val s1 = S ["CSCI", "ENG", "PHY"]; val s2 = S ["CHEM", "MATH"]; val is = product i1 s1; val si1 = product s1 i1; val si2 = product s2 i2; val sisi = product si1 si2; val siis1 = product si1 is; val siis2 = product si2 is; (* Verify each but print this result only *) |
fun union (I s1) (I s2) = I (unionList s1 s2)
| union (IS s1) (IS s2) = IS (unionList s1 s2)
| union (SISI s1) (SISI s2) = SISI (unionList s1 s2);
Test using the following. Show result of union tests only.
val i1 = I [1111,2222,3333];
val i2 = I [5555,6666];
val s1 = S ["CSCI", "ENG", "PHY"];
val s2 = S ["CHEM", "MATH"];
val is = product i1 s1;
val si1 = product s1 i1;
val si2 = product s2 i2;
val sisi = product si1 si2;
val siis1 = product si1 is;
val siis2 = product si2 is;union si1 si2; (* Show union results only *)
union siis1 siis2; (* Result is a big SIIS set *)
fun gtIx (x:int) (a:int, _) = a > x;
gtIx 4 (5,"red"); returns true
The following predicate function determines if the second tuple's second field of the second parameter is greater than the first parameter.
fun gtxxxI (x:int) ((_, _),(_, i:int)) = i > x;
gtxxxI 4 ((6,"blue"),("red",5)); returns true
Define the two predicate functions similarly to produce the following. Show
test results.
| gtSx "red" ("blue", 5); val it = false : bool gtSx "blue" ("red", 5); val it = true : bool eqxIxx 4 (("red",4),(6,"blue")); val it = true : bool eqxIxx 4 (("red",3),(6,"blue")); val it = false : bool |
fun gtIx (x:int) (a:int, _) = a > x;
gtIx 4 (5,"red");
val it = true : bool
(gtIx 4) (5,"red");
val it = true : bool
(gtIx 4) binds the first parameter x to 4 and returns the anonymous unary predicate function:
fn (a:int, _) => a > 4;
The effect is to convert a predicate function of two parameters into
a predicate function of one parameter for the relation a > 4.
This allows the more general case of the binary predicates in Question 3 to be
used in conjunction with the filter function discussed in class. The
filter function applies a unary predicate function to every element of
a list, returning those elements for which the predicate is true.
Using the normal filter function and the curried (gtIx 4) filters only those
tuples where the first field is greater than 4 from the list:
fun filter f [] = []
| filter f (h::t) = if (f h) then h :: (filter f t) else (filter f t);
filter (gtIx 4) [(7,"CSCI"),(3,"CHEM"), (6,"PHY")];
val it = [(7, "CSCI"), (6, "PHY")] : (int * string) list
Perform unit tests of these functions before moving on to Question 5, the following uses the filter function from class and tests using your predicates of Question 3. Show filter test results only.
| val i1 = I [1111,2222,3333]; val i2 = I [5555,6666]; val s1 = S ["CSCI", "ENG", "PHY"]; val s2 = S ["CHEM", "MATH"]; val is = product i1 s1; val si1 = product s1 i1; val si2 = product s2 i2; val sisi = product si1 si2; val siis1 = product si1 is; val siis2 = product si2 is; filter (gtSx "CSCI") [("CSCI",3.0),("PHY",4.0),("MATH",5.0)]; |
fun selectIS (IS L) f = IS (filter f L);
fun selectSISI (SISI L) f = SISI (filter f L);
With the appropriate curried predicate function, set selection is implemented:
selectIS isSET (gtIx 2222);
selectSISI sisiSET (gtxxxI 2222);
Implement selection operations for SI and SIIS sets for the test below. Show select test results only.
val i1 = I [1111,2222,3333];
val i2 = I [5555,6666];
val s1 = S ["CSCI", "ENG", "PHY"];
val s2 = S ["CHEM", "MATH"];
val is = product i1 s1;
val si1 = product s1 i1;
val si2 = product s2 i2;
val sisi = product si1 si2;
val siis1 = product si1 is;
val siis2 = product si2 is;
selectSI si1 (gtSx "CSCI");
selectSIIS siis1 (eqxIxx 2222);
fun gtIx (x:int) (a:int, _) = a > x;
gtIx 4 (5,"red");
val it = true : bool
(gtIx 4) (5,"red");
val it = true : bool
(gtIx 4) binds the first parameter x to 4 and returns the anonymous unary predicate function:
fn (a:int, _) => a > 4
so that:
(fn (a:int, _) => a > 4) (5, "red");
val it = true : bool
Used with the filter function:
filter (fn (a:int, _) => a > 4) [(7,"CSCI"),(3,"CHEM"),
(6,"PHY")];
val it = [(7, "CSCI"), (6, "PHY")] : (int * string) list
and with the selectIS function:
selectIS is (fn (a:int, _) => a > 2222);
val it = IS [(3333, "CSCI"), (3333, "ENG"), (3333, "PHY")]
: set
Use the selection implementation operations for SI and SIIS. Replace
the gtSx and eqxIxx below with anonymous functions. Show
select test results only.
| val i1 = I [1111,2222,3333]; val i2 = I [5555,6666]; val s1 = S ["CSCI", "ENG", "PHY"]; val s2 = S ["CHEM", "MATH"]; val is = product i1 s1; val si1 = product s1 i1; val si2 = product s2 i2; val sisi = product si1 si2; val siis1 = product si1 is; val siis2 = product si2 is; selectSI si1 (gtSx "CSCI"); selectSIIS siis1 (eqxIxx 2222); |
| val i1 = I [1111,2222,3333]; val i2 = I [5555,6666]; val s1 = S ["CSCI", "ENG", "PHY"]; val s2 = S ["CHEM", "MATH"]; val is = product i1 s1; val si1 = product s1 i1; val si2 = product s2 i2; val sisi = product si1 si2; val siis1 = product si1 is; val siis2 = product si2 is; difference si1 si2; difference siis1 siis2; |
Document last modified: