CSCI 2041 Lab04: Tuples and Records
- Due: 11:59pm Mon 10/08/2018
- Approximately 0.83% of total grade
- Submit to Canvas
- Lab exercises are open resource/open collaboration. You must submit your own work but you may freely discuss lab topics with other members of the class.
CODE DISTRIBUTION: lab04-code.zip
- Download the code distribution every lab
- See further setup instructions below
CHANGELOG:
- Mon Oct 1 08:49:50 CDT 2018
- The original version of the spec did not list the lab source files correctly.
1 Rationale
Like most modern programming languages, OCaml provides a variety of data types / structures built into the language. Knowing which type/structure to employ in a given situation requires one to be acquainted with their various trade-offs.
Lists and arrays have been discussed previously and have been identified as being homogeneous: all elements have the same type. This labs introduces Tuples, pairs in particular, and Records. These two are heterogeneous: they group multiple pieces of data of different kinds together.
Completing this lab will give a brief introduction to use of tuples and records in OCaml for basic data modeling.
Associated Reading / Preparation
- OCaml System Manual: Ch 1.4, 26 List Module: Association Lists
- Practical OCaml: Ch 5
Grading Policy
- Check-off 30%: Demonstrate to a TA that a student understands answers to questions. This must be done in person in groups of one or two. Check-offs can happen during the lab period of during a TA office hour.
- Submit 35%: Submit required files according to the lab instruction. This can be done at any time and from anywhere with a network connection. Submitting does not require attending lab. All students must submit files even if they were checked off in a group during lab.
- Survey 35%: Complete the Midterm Feedback Survey available on Canvas for full credit.
See the full policy in the syllabus.
2 Codepack
The codepack for the lab contains the following files:
File | State | Description |
---|---|---|
QUESTIONS.txt |
Edit | Answer questions in the file to complete the lab |
assoc_lists.ml |
Provided | Problem 1 file to analyze |
record_use.ml |
Provided | Problem 2 file to analyze |
3 Questions
Analyze the files in the provided codepack and answer the questions
given in QUESTIONS.txt
.
__________________ LAB 04 QUESTIONS __________________ - Name: (FILL THIS in) - NetID: (THE kauf0095 IN kauf0095@umn.edu) Answer the questions below according to the lab specification. Write your answers directly in this text file and submit it to complete the lab. PROBLEM 1: Pairs and Association Lists ====================================== Tuples allow multiple data of different types to be stored together. OCaml allows arbitrarily large tuples but in practice one works mostly with pairs (2-tuples) and triples (3-tuples). This problem explores *Association List* to map keys to values; these make extensive use of pairs (2-tuples). They are simple means of implementing the idea of a "map" from keys to values. In many functional programming contexts, the are implemented simply as an unordered list of pairs. This gives them linear complexity for operations like lookup. For small collections of key/values this is reasonable but as the collection goes large, one typically switches to using a sorted tree (logarithmic operations) or hash tables (amortized constant operations). (A) ~~~ Examine the first function in `assoc_lists.ml' which is called `assoc'. It operates on a key and an association list like the two provided as `alist1' and `alist2'. ,---- | let rec assoc query_key alist = | match alist with | | [] -> raise Not_found | | (key,value)::tail when query_key=key -> value | | _::tail -> assoc query_key tail | ;; | | let alist1 = [(9,"nine"); (5,"five"); (2,"two");] | let alist2 = [("nine",3.0); ("five",2.24); ("two",1.41); ("six",2.45)];; `---- In a REPL, load this code and run the function on the following inputs. - 9 and alist1 - 2 and alist1 - 7 and alist1 - "six" and alist2 - "one" and alist2 - 1 and alist2 Show your results below and explain what the function is doing. Also explain any errors for the above inputs and why the are happening. (B) ~~~ Examine the provided function `add_assoc' which adds an key/val pair to an association list if the key is not present or modifies the value associated with an existing key. ,---- | 1 (* return a list with the given key/value added; if the key already | 2 exists, changes association to the new value *) | 3 let rec add_assoc key value alist = | 4 match alist with | 5 | [] -> (key,value)::[] | 6 | (k,v) :: tail when key=k -> (key,value)::tail | 7 | (k,v) :: tail -> (k,v) :: (add_assoc key value tail) | 8 ;; `---- You may wish to run this function on some inputs like ,---- | # add_assoc 7 "seven" alist1;; `---- to get acquainted with its operation. Describe how this function works. Include the following in your answer. - Identify each case in the match/with statement as either a base case or a recursive case. - What situations does each case of the pattern matching expression handle? - How is pattern matching used to handle pairs in the list? (C) ~~~ At the bottom of `assoc_lists.ml' is a commented declaration for the `remove_assoc key alist' function. As the comment indicates, this should remove any existing association from a given list. ,---- | 1 (* return a list with the given key and associated value removed; if | 2 the given key is not present, no change is made to the list. Does | 3 not raise exceptions. *) | 4 (* let rec remove_assoc key alist = *) `---- Complete this function. Use a similar code structure that that which is used in `add_assoc'. Demonstrate that the function works correctly in a REPL by removing some associations from `alist1' and `alist2' Note: Built-in Association Lists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OCaml has functions operating on Association Lists built in. They are available in the `List' module and can be called as follows. ,---- | # let alist = [(9, "nine"); (5, "five"); (2, "two")];; | val alist : (int * string) list = [(9, "nine"); (5, "five"); (2, "two")] | | # List.assoc 2 alist;; | - : string = "two" | | # List.assoc 6 alist;; | Exception: Not_found. | | # List.remove_assoc 5 alist;; | - : (int * string) list = [(9, "nine"); (2, "two")] `---- More details are in the module documentation for list here: [https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html#1_Associationlists] Note that the semantics for standard association lists are somewhat different than those we implemented here: keys may be duplicated and "left-most" bindings are returned. This makes adding on more efficient at the expense of memory and removal complexity. PROBLEM 2: Records ================== Records are types defined to have multiple named *fields* of different kinds. These are similar to C's structs and Java's objects. This problem explores basic record definition and use. (A) ~~~ Examine the provided source file `record_use.ml'. The first few lines of this file contain a type declaration for a new record type called `force_user'. ,---- | 1 (* record type declaration *) | 2 type force_user = { | 3 name : string; (* field 1 *) | 4 darkside : bool; (* field 2 *) | 5 episodes : int list; (* field 3 *) | 6 };; `---- Below it are several examples of creating `force_user' records. Make use of this pattern to declare some additional `force_user' records and paste your new code below. Demonstrate that your code works properly by loading it in a REPL. (B) ~~~ Record fields are accessed with dot notation. This can be done in individual statements or during execution of functions. The following code segments from `record_use.ml' show some examples. ,---- | 1 (* field access *) | 2 let last_jedi1 = luke.name;; | 3 let last_jedi2 = rey.name;; | 4 let sith_reigh = List.length sidious.episodes;; | 5 | 6 (* functions on records *) | 7 let name_of user = (* retrieve the name *) | 8 user.name | 9 ;; | 10 | 11 let episode_count user = (* count episodes *) | 12 List.length user.episodes | 13 ;; `---- Demonstrate in a REPL some field accesses on the data you have defined like - Accessing the darkside field - Measuring the length of a name field with String.length - Appending two episode field lists with @ (append) operator (C) ~~~ Consider the function `seduced': it takes a `force_user' as an argument and creates a new version of it using the `with' syntax. ,---- | 1 let seduced user = (* new record with field changed *) | 2 let dark_user = {user with darkside=true} in | 3 dark_user | 4 ;; `---- Use a REPL to demonstrate how `seduced' works. Determine whether this function actually changes the original record or not. Explain your answer. (D) ~~~ Write a function `sequel_appearance'. It takes a `force_user' and an integer as parameters. It creates a new `force_user' record from the old one with the integer parameter appended to the end of the `episodes' field using the @ operator. Its type and use are demonstrated below. ,---- | # #use "record_use.ml";; | val sequel_appearance : force_user -> int -> force_user = <fun> | | # rey;; | - : force_user = {name = "Rey"; darkside = false; episodes = [7; 8]} | # sequel_appearance rey 9;; | - : force_user = {name = "Rey"; darkside = false; episodes = [7; 8; 9]} | | # vader;; | - : force_user = | {name = "Anakin Skywalker"; darkside = true; episodes = [1; 2; 3; 4; 5; 6]} | # sequel_appearance vader 10;; | - : force_user = | {name = "Anakin Skywalker"; darkside = true; episodes = [1; 2; 3; 4; 5; 6; 10]} `---- PROBLEM 3: Feedback Survey ========================== For full credit on this lab, complete the Midterm Feedback Survey which is available on Canvas - Click "Quizzes" - Select "Midterm Feedback" - The survey is Anonymous and graded only on completion
4 What to Understand
Ensure that you understand
- Basics tuple construction using commas
- Applications of patter matching to tuples and lists of tuples
- Basic syntax to declare a new record type and access its fields with dot notation
- Use of the
with
syntax to produce new records from old ones with selectively altered fields
5 Getting Credit: Submit and Check-off
- Check-off your answers with a TA in person during lab or office hours.
- Submit your completed
QUESTIONS.txt
file to Canvas under the appropriate lab heading. Make sure to paste in any new code and answers you were to write at appropriate locations in the file.