├── .DS_Store ├── README.md ├── discussions ├── .DS_Store ├── d0_git │ └── README.md ├── d10_lambda_calc │ ├── README.md │ └── lambda_calc_answers.png ├── d11_rust │ ├── README.md │ └── src │ │ ├── error.rs │ │ └── solution.rs ├── d1_ruby │ ├── README.md │ └── src │ │ ├── disc1.rb │ │ ├── disc1_sol.rb │ │ ├── rectangle.rb │ │ └── rectangle_sol.rb ├── d2_ruby2 │ └── README.md ├── d3_ocaml │ └── README.md ├── d4_hof │ ├── README.md │ ├── d4_skeleton.ml │ └── d4_sol.ml ├── d5_project_review │ └── README.md ├── d6_nfa_dfa │ ├── README.md │ ├── nfa-accept.png │ ├── nfa-e-closure.png │ ├── nfa-move.png │ ├── nfa2.png │ ├── nfa_to_dfa_1_sol.jpg │ └── nfa_to_dfa_2_sol.png ├── d7_opsem │ ├── README.md │ └── solutions │ │ ├── opsem1.png │ │ └── opsem2.png ├── d8_cfg │ └── README.md └── d9_parsing │ ├── .DS_Store │ ├── README.md │ └── src │ ├── .DS_Store │ ├── interpreter.ml │ ├── interpreter.mli │ ├── interpreter.skeleton.ml │ ├── lexer.ml │ ├── lexer.mli │ ├── lexer.skeleton.ml │ ├── parser.ml │ ├── parser.mli │ └── parser.skeleton.ml ├── lecture_code ├── math-ew │ ├── input.txt │ ├── lec1.rb │ ├── lec2.rb │ └── lec3.rb ├── may4 │ ├── lec1.txt │ ├── lec2.txt │ └── lec3.txt ├── ocaml │ ├── expr.ml │ ├── expresions.txt │ ├── hof.ml │ ├── hw.ml │ └── lets_lists_patterns.ml ├── review │ ├── lec1.review │ ├── lec2.review │ └── lec3.review ├── ruby │ ├── cb.rb │ ├── hw.rb │ ├── int.rb │ ├── methods.rb │ ├── oop.rb │ ├── regex │ │ ├── file.rb │ │ ├── file.txt │ │ ├── file2.txt │ │ └── file3.txt │ └── typing.rb └── rust │ ├── fact.rs │ ├── factorial.rs │ ├── lec1 │ ├── lec2 │ └── lec3 └── projects ├── project1b ├── README.md └── test │ └── public │ ├── inputs │ ├── grammar1.txt │ ├── grammar2.txt │ ├── grammar3.txt │ ├── words1.txt │ ├── words2.txt │ └── words3.txt │ └── public.rb ├── project2a └── README.md ├── project2b ├── GRADESCOPE_SUBMIT.md ├── README.md └── from_pre_in.pdf ├── project3 ├── GRADESCOPE_SUBMIT.md ├── README.md ├── SETS.md ├── images │ ├── m_viz.png │ └── n_viz.png └── subset.pdf ├── project4a ├── GRADESCOPE_SUBMIT.md └── README.md ├── project4b ├── .submit ├── GRADESCOPE_SUBMIT.md └── README.md └── project5 ├── .submit └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### CMSC330 Spring 2023 2 | 3 | List of projects: 4 | 5 | + [Project 0](https://classroom.github.com/a/uXj0y7qf) 6 | + [Project 1a](https://classroom.github.com/a/qe6I5Kns) 7 | + [Project 1b](https://classroom.github.com/a/3g5EiMZl) 8 | + [Project 1b (updated README/tests)](https://github.com/cmsc330-umd/spring23/tree/main/projects/project1b) 9 | + [Project 2a](https://classroom.github.com/a/JaeYcDGO) ([README](https://github.com/cmsc330-umd/spring23/tree/main/projects/project2a)) 10 | + [Project 2b](https://classroom.github.com/a/GCQAZiE4) ([README](https://github.com/cmsc330-umd/spring23/tree/main/projects/project2b)) 11 | + [Project 3](https://classroom.github.com/a/CEG7_xgA) ([README](https://github.com/cmsc330-umd/spring23/tree/main/projects/project3)) 12 | + [Project 4a](https://classroom.github.com/a/pErNAnwo) ([README](https://github.com/cmsc330-umd/spring23/tree/main/projects/project4a)) 13 | + [Project 4b](https://classroom.github.com/a/0TS9TRaA) ([README](https://github.com/cmsc330-umd/spring23/tree/main/projects/project4b)) 14 | + [Project 5](https://classroom.github.com/a/8F_d4oNX) ([README](https://github.com/cmsc330-umd/spring23/tree/main/projects/project5)) 15 | 16 | List of discussions: 17 | + [Discussion 0 - Git](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d0_git) 18 | + [Discussion 1 - Ruby](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d1_ruby) 19 | + [Discussion 2 - Ruby Part 2](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d2_ruby2) 20 | + [Discussion 3 - OCaml](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d3_ocaml) 21 | + [Discussion 4 - Higher Order Functions](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d4_hof) 22 | + [Discussion 5 - Project Review](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d5_project_review) 23 | + [Discussion 6 - NFA and DFA](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d6_nfa_dfa) 24 | + [Discussion 7 - Operational Semantics](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d7_opsem) 25 | + [Discussion 8 - Context Free Grammars](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d8_cfg) 26 | + [Discussion 9 - Lexing, Parsing, Interpreting](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d9_parsing) 27 | + [Discussion 10 - Lambda Calculus](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d10_lambda_calc) 28 | + [Discussion 11 - Rust](https://github.com/cmsc330-umd/spring23/tree/main/discussions/d11_rust) 29 | -------------------------------------------------------------------------------- /discussions/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/.DS_Store -------------------------------------------------------------------------------- /discussions/d0_git/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 0 - Friday, January 27th 2 | 3 | ## Reminders 4 | 1. Project 0 due February 4th 11:59PM 5 | 6 | ## What is Git? 7 | 8 | 1. Git is an open-source version control system. 9 | 2. If you don’t have Git installed, navigate to this link and install it https://git-scm.com/book/en/v2/Getting-Started-Installing-Git 10 | 3. Make sure to set up an SSH key: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent 11 | 12 | ## Navigate to class github (located on the class page: https://bakalian.cs.umd.edu/330) 13 | 14 | 1. Click on project 0 15 | 2. Accept project 0 16 | 17 | ## Cloning the repository: 18 | 19 | 1. `git clone ` 20 | 2. Go into your new repository: `cd ` 21 | 22 | ## Staging, committing, and pushing changes: 23 | 24 | 1. Make text file in the repository directory on your machine: `touch hello.txt` 25 | 2. Add: `git add .` 26 | 3. Commit: `git commit -m “Add new text file”` 27 | 4. Push: `git push` 28 | 29 | ## Pulling changes: 30 | 1. Edit text file on GitHub desktop (in your browser) 31 | 2. Pull: `git pull` 32 | 33 | ## Complete project0 34 | -------------------------------------------------------------------------------- /discussions/d10_lambda_calc/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 10 - Friday, April 14th 2 | 3 | ## Reminders 4 | * Quiz 4 is **today** 5 | * Exam 2 is on April 20th 6 | * Project 4a/4b **deadline extended** to April 30th (10% extra credit if you submit by initial due date of April 23rd) 7 | 8 | ## Lambda Calculus 9 | 10 | ### Call by Value 11 | "eager evaluation"
12 | before doing a beta reduction, we make sure the argument cannot, itself, be further evaluated 13 | 14 | (λz. z) ((λy. y) x) → (λz. z) x → x 15 | 16 | ### Call by Name 17 | "lazy evaluation"
18 | we can specifically choose to perform beta-reduction *before* we evaluate the argument 19 | 20 | (λz. z) ((λy. y) x) → (λy. y) x → x 21 | 22 | 23 | ### Exercises 24 | 25 | 1) (λa. a) b 26 | 27 | **Make the parentheses explicit in the following expressions:** 28 | 29 | 2) a b c 30 | 31 | 3) λa. λb. c b 32 | 33 | 4) λa. a b λa. a b 34 | 35 | **Identify the free variables in the following expressions:** 36 | 37 | 5) λa. a b a 38 | 39 | 6) a (λa. a) a 40 | 41 | 7) λa. (λb. a b) a b 42 | 43 | **Apply alpha-conversions to the following:** 44 | 45 | 8) λa. λa. a 46 | 47 | 9) (λa. a) a b 48 | 49 | 10) (λa. (λa. (λa. a) a) a) 50 | 51 | **Apply beta-reductions to the following:** 52 | 53 | 11) (λa. a b) x b 54 | 55 | 12) (λa. b) (λa. λb. λc. a b c) 56 | 57 | 13) (λa. a a) (λa. a a) 58 | -------------------------------------------------------------------------------- /discussions/d10_lambda_calc/lambda_calc_answers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d10_lambda_calc/lambda_calc_answers.png -------------------------------------------------------------------------------- /discussions/d11_rust/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 11 - Friday, April 28th 2 | 3 | ## Reminders 4 | * Project 4a and 4b due April 30th (extended deadline) 5 | * Quiz 5 **next week** on May 5th in discussion 6 | 7 | ## What is Rust? 8 | 9 | Modern language designed for concurrency; it's similar to C++ and OCaml, but does it in a fast, type-safe, and thread-safe manner 10 | * How does it achieve speed and safety? It avoids Garbage Collection, and instead uses rules for memory management 11 | 12 | `let mut x = String::from("hello");` <- Mutability 13 | 14 | `do_something(&mut x);` <- Borrowing, avoids ownership change 15 | 16 | `println("{}",x);` 17 | 18 | ### Mutability 19 | 20 | * Variables can either be declared as mutable (`mut`) or immutable 21 | * Similar to `const` in C 22 | * Mutable means the variable can be reassigned, e.g. `let mut x = 0; x = x + 5;` 23 | 24 | ### Ownership 25 | 26 | #### Terms 27 | 28 | * **Value**: Data stored in memory (Strings, ints, structs, etc...), values must always be owned by exactly one variable 29 | * **Variable**: may own a value, or be a reference to a value 30 | * **Scope**: The area where a `variable` is defined, usually from the `let` statement until end of its codeblock (`}`) 31 | * **Lifetime**: The area where a `value` is defined, because `value`s can change owners, this is not always the same as the scope of the variable it was initally owned by 32 | 33 | 34 | #### Rules 35 | 36 | * Ownership is a technique used to automatically free variables 37 | * Each piece of data has a single owner(variable) at a time. When its owner goes out of scope, its value is dropped from memory 38 | * Ownership changes through two operations 39 | * Variable assignment 40 | * Ownership of the value transfers to the new variable, the old variable becomes invalid (no data) 41 | * Note that primitives like integers, booleans, etc. do not transfer ownership on assignment. Primitives implement the `Copy` trait, so their value can simply be copied to new variables 42 | * E.g. 43 | 44 | `let s1 = String::from("hello");` <- s1 is owner 45 | 46 | `let s2 = s1;` <- Ownership is transferred from s1 to s2 47 | 48 | `println!("{}",s1);` <- Error, s1 is now invalid 49 | 50 | * Function call 51 | * When a variable is passed into a function, ownership is transferred to the function, so the variable is invalidated after the function is run 52 | * `let s1 = String::from("hello"); do_something(s1);` 53 | * Ownership was transferred from s1 to function parameter; s1 is now invalidated 54 | 55 | ### Borrowing/References 56 | 57 | * We can use references to get around ownership issues 58 | * Borrowing is similar to pointers in C, two types 59 | * Mutable ref, `&mut` - Can edit variable, only for mutable variables, only one may exist at any point in time 60 | * Immutable ref, `&` - Can't edit 61 | * Allows us to pass in references to functions, preventing ownership from going out of scope 62 | * Also used for things like iteration; when looping through list, get a series of references to elements in list 63 | * One limitation: Can only either have `1 mutable ref` or `many immutable refs` at any given time 64 | * This prevents weird write errors 65 | * Exemplified by String class; `&str` is a read-only pointer to String, whereas String class is similar to array of chars 66 | 67 | Example with .iter(): 68 | 69 | ```ocaml 70 | let mut arr = [1,2,3]; 71 | for &i in arr.iter() { 72 | println!("{}",i); 73 | } 74 | ``` 75 | 76 | 77 | 78 | What does this mean when you write programs? 79 | 80 | 81 | 1. Make sure you know which variables are mutable and immutable 82 | 2. Be aware of who owns certain variables, and pass around references to make sure ownership doesn't go out 83 | 84 | Some common errors are 85 | 86 | 87 | 1. Variable mutability 88 | 2. Using variable after it goes out of scope 89 | 3. Passing in regular variable instead of reference 90 | 4. Failing to return correct value from function 91 | 5. Incorrect types (reference when regular variables should be used, etc.) 92 | 93 | ## Debugging Problems 94 | 95 | Each of the functions in error.rs has an error; fix the error 96 | 97 | Solutions in correct.rs 98 | -------------------------------------------------------------------------------- /discussions/d11_rust/src/error.rs: -------------------------------------------------------------------------------- 1 | pub fn sum_evens(i: i32, j: i32) -> i32 { 2 | 3 | let sum = 0; 4 | 5 | for k in i..j { 6 | 7 | if k % 2 == 0 { 8 | 9 | sum += k; 10 | 11 | } 12 | 13 | } 14 | 15 | sum 16 | 17 | } 18 | 19 | pub fn distance((ax, ay): (f64, f64), (bx, by): (f64, f64)) -> f64 { 20 | 21 | ((bx - ax).powf(2) + (by - ay).powf(2)).sqrt() 22 | 23 | } 24 | 25 | pub fn raise_1(arr: &mut [i32]) { 26 | 27 | for i in arr { 28 | 29 | i += 1; _ 30 | 31 | } 32 | 33 | } 34 | 35 | 36 | pub fn add_hello(a: String) { 37 | 38 | a.push_str("hello"); 39 | 40 | } 41 | 42 | pub fn create_hello_world()->String { 43 | 44 | let mut s = String::from(""); 45 | 46 | add_hello(s); 47 | 48 | s.push_str("world"); 49 | 50 | return s; 51 | 52 | } 53 | 54 | 55 | pub fn get_first_elem(a: &Vec) -> u32 { 56 | 57 | if(a.len() == 0) { 58 | 59 | return 0; 60 | 61 | } 62 | 63 | return a.get(0); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /discussions/d11_rust/src/solution.rs: -------------------------------------------------------------------------------- 1 | pub fn sum_evens(i: i32, j: i32) -> i32 { 2 | 3 | let mut sum = 0; // Change sum to mut 4 | 5 | for k in i..j { 6 | 7 | if k % 2 == 0 { 8 | 9 | sum += k; 10 | 11 | } 12 | 13 | } 14 | 15 | sum 16 | 17 | } 18 | 19 | pub fn distance((ax, ay): (f64, f64), (bx, by): (f64, f64)) -> f64 { 20 | 21 | ((bx - ax).powi(2) + (by - ay).powi(2)).sqrt() // should be powi; i is for integer function, f is for float) 22 | 23 | } 24 | 25 | pub fn raise_1(arr: &mut [i32]) { 26 | 27 | for i in arr { 28 | 29 | *i += 1; // i is a reference, so should be *i) 30 | 31 | } 32 | 33 | } 34 | 35 | pub fn add_hello(a: &mut String) { // Make it &mut 36 | 37 | a.push_str("hello"); 38 | 39 | } 40 | 41 | pub fn create_hello_world()->String { 42 | 43 | let mut s = String::from(""); 44 | 45 | add_hello(&mut s); // &mut s and make add_hello(a: &mut String)) 46 | 47 | s.push_str("world"); 48 | 49 | return s; 50 | 51 | } 52 | 53 | pub fn get_first_elem(a: &Vec) -> u32 { 54 | 55 | if(a.len() == 0) { 56 | 57 | return 0; 58 | 59 | } 60 | 61 | return *a.get(0).unwrap(); //Unwrap the some and dereference 62 | 63 | } 64 | -------------------------------------------------------------------------------- /discussions/d1_ruby/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 1 - Friday, February 3rd 2 | 3 | ## Reminders 4 | 1. Project 1a due Sunday, February 5th 11:59PM 5 | 2. Quiz 1 next Friday, February 10th **in discussion** 6 | 7 | ## Code Blocks 8 | 9 | A code block is like a special kind of method. They allow you to package code and pass it in as a variable. The fundamental idea is passing code as data. 10 | ```rb 11 | { |y| x = y + 1; puts x } 12 | ``` 13 | is almost the same as 14 | ```rb 15 | def m(y) 16 | x = y + 1 17 | puts x 18 | end 19 | ``` 20 | This is called **higher-order programming**. In other words, methods take other (almost-)methods as arguments. 21 | 22 | ### `each` 23 | Code blocks in the `each` method do not modify the array. 24 | ```rb 25 | a = [1,2] 26 | a.each { |x| x = x*x } 27 | puts a[1] 28 | # outputs 2, NOT 4 29 | ``` 30 | 31 | ### `find` 32 | This method returns the first element `a` for which the code block returns true. 33 | ```rb 34 | [1, 2, 3, 4, 5].find { |y| y % 2 == 0 } 35 | # returns 2 36 | ``` 37 | 38 | ### `collect` 39 | The method applies the given code block to each element of an array and returns a new array. 40 | Using `collect!` modifies the array. 41 | ```rb 42 | [5, 4, 3].collect { |x| -x } 43 | # returns [-5, -4, 3] 44 | ``` 45 | 46 | ## Code Block Exercises 47 | 48 | 1. Create a code block to calculate the sum of elements in the array [1, 2, 3, 4, 5] 49 | 2. Multiply all elements of the same array by 2 50 | 3. Given a hashmap of countries to their populations, create a code block that will print "population of [country] is [population] million" for each element in the hashmap 51 | 4. Call a code block with yield (example below) 52 | ```rb 53 | def count(x) 54 | return "No block" unless block_given? 55 | for i in (1..x) 56 | yield i 57 | end 58 | end 59 | 60 | count(5) { |x| puts x + 2 } 61 | ``` 62 | Write a function that takes in a comma-delimited string and uses `yield` to invoke a code block that outputs each word on a separate line. 63 | 64 | ## Procs 65 | 66 | Think of these as making an object out of a code block. You can invoke Procs via `call`. Note that a code block is not an object. 67 | 68 | The syntax is very similar to creating a code block: Consider a very simple code block that takes in a number `x` and returns the area of a square with side length `x`. 69 | 70 | ```rb 71 | square = Proc.new{ |x| x**2} 72 | puts square.call(2) 73 | ``` 74 | 75 | You can also pass in multiple parameters into a proc as follows: 76 | 77 | ```rb 78 | list_two = Proc.new{|first, second| puts "#{first} and #{second} were passed in"} 79 | ``` 80 | 81 | Since procs are objects, it is possible to pass them as arguments into methods: 82 | 83 | ```rb 84 | def do_something_on_variable(variable, something) 85 | something.call(variable) 86 | end 87 | 88 | puts do_something_on_variable(2, square) # outputs 4 89 | ``` 90 | 91 | You can also create nested Procs: 92 | 93 | ```rb 94 | def say(y) 95 | t = Proc.new {|x| Proc.new {|z| z+x+y }} 96 | return t 97 | end 98 | s = say(2).call(3) 99 | puts s.call(4) # outputs 9 100 | ``` 101 | 102 | Keep this type of "function nesting" in the back of your head; we'll use it (a *lot*) when coding in OCaml! 103 | 104 | ## Proc Exercise 105 | 106 | ### `distance` 107 | Takes in coordinates `x_1`, `y_1`, `x_2`, `y_2` representing points $(x_1, y_1)$ and $(x_2, y_2)$ and outputs the Euclidean distance between them. 108 | Remember that you can consult Ruby documentation for standard mathematical operations! 109 | 110 | ```rb 111 | sample = distance.call(0, 0, 3, 4) # outputs 5.0 112 | ``` 113 | 114 | ## Rectangle Class 115 | 116 | We will now implement a simple class in Ruby in order to highlight fundamental OOP concepts. 117 | 118 | A `Rectangle` represents a rectangle shape. The methods below will be implemented in the `Rectangle` class in [rectangle.rb](src/rectangle.rb). 119 | 120 | #### `initialize(length, width)` 121 | 122 | - **Type**: `(Integer, Integer) -> _` 123 | - **Description**: Given a length and width for the rectangle, store them in the `Rectangle` object. You should perform any initialization steps for the `Rectangle` instance here. The return value of this function does not matter. Note that we must keep track of the number of `Rectangle` objects that have been instantiated. 124 | - **Examples**: 125 | ```ruby 126 | square = Rectangle.new(5, 5) 127 | rectangle = Rectangle.new(2, 3) 128 | ``` 129 | 130 | Notice that we can also omit parentheses when inputting parameters. 131 | 132 | #### `getArea()` 133 | 134 | - **Type**: `_ -> Integer` 135 | - **Description**: Return the area of a `Rectangle` 136 | - **Examples**: 137 | ```ruby 138 | square = Rectangle.new(5, 5) 139 | rectangle = Rectangle.new(2, 3) 140 | square.getArea() # Returns 25 141 | rectangle.getArea() # Returns 6 142 | ``` 143 | 144 | Notice that we can explicitly use the keyword `return` to return the area. If we choose to omit the `return` keyword, the method will return the last statement in the method. 145 | 146 | #### `self.getNumRectangles(n)` 147 | 148 | - **Type**: `(Integer) -> Integer` 149 | - **Description**: Return the number of `Rectangles`s whose area is less than n. Hint: you should use a static data structure to keep track of this. 150 | - **Examples**: 151 | ```ruby 152 | Rectangle.getNumRectangles(20) # Returns 0 153 | square = Rectangle.new(5, 5) 154 | rectangle = Rectangle.new(2, 3) 155 | Rectangle.getNumRectangles(20) # Returns 1 156 | Rectangle.getNumRectangles(30) # Returns 2 157 | ``` 158 | -------------------------------------------------------------------------------- /discussions/d1_ruby/src/disc1.rb: -------------------------------------------------------------------------------- 1 | def sum() 2 | a = [1,2,3,4,5] 3 | sum = 0 4 | # insert code block here 5 | 6 | puts sum 7 | end 8 | 9 | def multiply() 10 | a = [1,2,3,4,5] 11 | # insert code block here 12 | 13 | puts a.join(',') 14 | end 15 | 16 | def population() 17 | countries = {} 18 | countries["USA"] = 319 19 | countries["Italy"] = 60 20 | 21 | # insert code block here 22 | end 23 | 24 | def splitString(s) 25 | # insert code here 26 | end 27 | 28 | # call splitString here (param: "welcome,to,ruby,discussion") with code block 29 | 30 | 31 | -------------------------------------------------------------------------------- /discussions/d1_ruby/src/disc1_sol.rb: -------------------------------------------------------------------------------- 1 | def sum() 2 | a = [1,2,3,4,5] 3 | sum = 0 4 | a.each { |x| sum += x } 5 | 6 | puts sum 7 | end 8 | 9 | def multiply() 10 | a = [1,2,3,4,5] 11 | a.collect! { |x| x*2 } 12 | 13 | puts a.join(',') 14 | end 15 | 16 | def population() 17 | countries = {} 18 | countries["USA"] = 319 19 | countries["Italy"] = 60 20 | 21 | countries.each { |k,v| 22 | puts "population of #{k} is #{v} million" 23 | } 24 | end 25 | 26 | def splitString(s) 27 | for word in s.split(',') 28 | yield word 29 | end 30 | end 31 | 32 | 33 | distance = Proc.new {|x_1, y_1, x_2, y_2| puts Math.sqrt((x_2 - x_1)**2 + (y_2 - y_1)**2) } 34 | 35 | 36 | sum() 37 | multiply() 38 | population() 39 | splitString("welcome,to,ruby,discussion") { |x| puts x } 40 | distance.call(0, 0, 3, 4) 41 | 42 | -------------------------------------------------------------------------------- /discussions/d1_ruby/src/rectangle.rb: -------------------------------------------------------------------------------- 1 | class Rectangle 2 | def initialize(length, width) 3 | 4 | end 5 | 6 | def getArea() 7 | 8 | end 9 | 10 | def self.getNumRectangles(n) 11 | 12 | end 13 | end -------------------------------------------------------------------------------- /discussions/d1_ruby/src/rectangle_sol.rb: -------------------------------------------------------------------------------- 1 | class Rectangle 2 | @@area = Hash.new 0 3 | 4 | def initialize(length, width) 5 | @length = length 6 | @width = width 7 | @@area[length * width] += 1 8 | end 9 | 10 | def getArea 11 | return @length * @width 12 | end 13 | 14 | def self.getNumRectangles(n) 15 | count = 0 16 | for k, v in @@area 17 | if k <= n 18 | count += v 19 | end 20 | end 21 | count 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /discussions/d2_ruby2/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 2 - Friday, February 10th 2 | 3 | ## Reminders 4 | 1. Quiz 1 is **TODAY**! 5 | 2. Project 1b **NEW DUE DATE** is February 19th 11:59PM 6 | 3. Don't forget to copy over the **NEW README AND TESTS** for Project 1b! See Piazza post [@308](https://piazza.com/class/lctd1gtoyd76m8/post/308) 7 | 8 | ## `generatePOS(sentence)` 9 | 10 | Given a string `sentence`, return an array of the part of speech (POS) of each word in the sentence. You may assume that the words in the sentence are in English, and each word is separated by exactly one space. There is no punctuation at the end of the sentence. 11 | 12 | + example: `generatePOS("the blue car")` -> `["DET", "ADJ", "NOU"]` 13 | 14 | How would you implement `generatePOS`? 15 | 16 | What data structure would you use to store the information about the words in the English language? 17 | -------------------------------------------------------------------------------- /discussions/d3_ocaml/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 3 - Friday, February 17th 2 | 3 | ## Reminders 4 | 1. Project 1b due Sunday, February 19th 11:59PM 5 | 2. Quiz 1 regrade requests open until February 22nd 6 | 3. Quiz 2 **next Friday**, February 24th **in discussion** 7 | 8 | ## Introduction 9 | 10 | This week, we dive into Ocaml in discussions. We will be covering a breadth of material in Ocaml. Projects 2 to 4 are in Ocaml. So, please make sure you understand the fundamentals of the language as best as possible. Today, we will be covering **Ocaml expressions, values, and types, let bindings, let expressions, lists, pattern matching, functions, and recursive functions `rec`**. 11 | 12 | ## Part 1: Ocaml expressions, values, and types 13 | 14 | Some basics of Ocaml. Ocaml is a compiled and bootstrapped language. It is implicitly typed. That means, the compiler infers the type of your variables and values at compile time. Ocaml is also statically typed, meaning once the type of a variable is infered, the variable must abide by the type throughout its scope. Everything in Ocaml is immutable. Everything means everything. Once you initialize a variable, you cannot change throughout its scope. You should redefine it to change it. That being said, `=` is an equality operator and not the assignment operator outside `let` expressions. 15 | 16 | Some primitive built-in data types are `int`, `float`, `char`, `string`, `bool`, and `unit`. Other composite data types include `tuples`, `lists`, `option`, and variants. 17 | 18 | We know the primitive data types but we will learn more about the others later down in the discussion. Arithmetic operators in Ocaml are not overloaded. So, you can use `+`, `-`, `*`, `/` on two ints but not on floats. For floats, they are `+.`, `-.`, `*.`, `/.`. **Notice the period**. 19 | 20 | Expressions are something that evaluates to some value. Example: `1 + 2`, `2 < 3`, `"hello"`. 21 | 22 | ## Part 2: Let bindings and Let expressions 23 | 24 | Almost everything in Ocaml is an expression , say `e`. An expression will evaluate to some value of type, say `t`. 25 | 26 | Examples: 27 | - `1: int` 28 | - `true: bool` 29 | - `'e': char` 30 | 31 | The `let` syntax is the main way to bind a name to a value. Simply: 32 | 33 | ```ocaml 34 | let name = value;; (* syntax *) 35 | let num1 = 5;; (* type: int *) 36 | let num2 = 6;; (* type: int *) 37 | let num3 = num1 + num2;; (* type: int *) 38 | ``` 39 | 40 | We use `let` to create expressions as well. Remember that expressions evaluate to some values. So, the variables initialized in the let expressions are limited to the expression in terms of scope. 41 | 42 | Examples: 43 | 44 | ```ocaml 45 | let x = 8 in x;; (* will evaluate to 8 *) 46 | let x = 10 in let y = 15 in x + y;; (* nested let expressions *) 47 | let x = 5 in let y = 7 in if x > y then "bigger" else "smaller";; (* expression can be another expression *) 48 | ``` 49 | 50 | ## Part 3: Functions and the `rec` keyword 51 | 52 | Functions, conventionally, are multiline reusable code that might or might not depend on other variables (arguments). To denote the notion of functions in Ocaml, we can treat the functions as expressions i.e. something that can evaluate to a value. Technically, a function processes the input and generates an output. Putting multiple expressions together can work the same magic. So, we use `let` bindings to bind expression(s) and parameters to some name to make functions. 53 | 54 | Example: 55 | 56 | ```ocaml 57 | let my_function a = a;; (* type 'a -> 'a *) 58 | ``` 59 | analogous to (java) 60 | ```java 61 | T my_function(T a) { 62 | return a; 63 | } 64 | ``` 65 | 66 | Raising the complexity of the functions: 67 | ```ocaml 68 | let my_func param1 param2 = param1 + param2;; (* type: int -> int -> int *) 69 | let to_arr a b = [a; b];; (* type: 'a -> 'a -> 'a list *) 70 | ``` 71 | analogous to (java) 72 | ```java 73 | int my_func(int param1, int param2) { 74 | return param1 + param2; 75 | } 76 | 77 | T[] to_arr(T a, T b) { 78 | return {a, b}; 79 | } 80 | ``` 81 | 82 | ```ocaml 83 | let check_empty_string str_param = 84 | if str_param = "" then true else false;; (* type: string -> boolean *) 85 | 86 | let check_a_string str_param = 87 | if str_param = "a" then true else "invalid string";; (* will fail to compile *) 88 | ``` 89 | 90 | Notice how each branch in a function (maybe if-else or pattern matching) should return the same data type. 91 | 92 | The general pattern for determining the type of any function is: 93 | 94 | `first_param_type -> second_param_type -> ... -> last_param_type -> return_type`. 95 | 96 | Let's practice writing functions with specified types! 97 | 98 | #### `'a -> 'a -> bool` 99 | 100 | #### `('a -> 'b) -> 'a -> 'b -> bool` 101 | 102 | #### `int -> (int -> float) -> string` (Challenge) 103 |
104 | 105 | ### Recursive functions 106 | 107 | The use of `rec` keyword makes a function recursive. You do not need to make recursive calls, but if you want to, you need the `rec` keyword. 108 | 109 | ```ocaml 110 | let rec factorial num = 111 | if num = 1 then 1 else num * (factorial (num - 1)) (* int -> int *) 112 | ``` 113 | 114 | ## Part 4: Lists 115 | 116 | Lists are analogous to arrays to other languages with a difference that the Ocaml lists cannot be indexed. So, recursion is the prime way of iterating over a list and pattern-matching to access an element. The lists are homogenous in nature and the elements are separated by `;`. 117 | 118 | Examples: 119 | ```ocaml 120 | let my_list = [1;2;3];; 121 | let my_second_list param_a param_b = [param_a; param_b] in my_second_list 1 2;; 122 | let my_third_list = "first" :: ["second"; "third"];; 123 | ``` 124 | 125 | You preppend to a list using a cons `::` operator. 126 | 127 | Let's practice with lists! 128 | 129 | #### `int -> int -> float list` 130 | 131 | #### `('a -> 'b) -> 'a -> 'b list -> 'b list` 132 |
133 | 134 | ## Part 5: Pattern matching 135 | 136 | Pattern matching is like regular expressions for values. You match the values against a desired pattern to validate that value, extract subvalues out of it, or even manipulate the subvalues. 137 | 138 | Syntax: 139 | ```ocaml 140 | match value with 141 | pattern1 -> code if it match pattern1 142 | | pattern2 -> code if it match pattern2 143 | . 144 | . 145 | | _ -> default code;; 146 | ``` 147 | 148 | - List pattern matching 149 | 150 | ```ocaml 151 | let my_list [ 1; 2; 3; 4; 5];; 152 | 153 | let rec add_one lst = match lst with 154 | [] -> [] 155 | | h :: t -> (h + 1) :: (add_one t) 156 | in add_one my_list;; 157 | ``` 158 | 159 | You can even have multiple levels of patterns. 160 | 161 | ```ocaml 162 | let check_min_len lst = match lst with 163 | [] -> "zero" 164 | | a :: t -> "at least one" 165 | | a :: b :: t -> "at least two" 166 | | a :: b :: c :: t -> "at least three" 167 | | _ -> "at least four";; 168 | ``` 169 | -------------------------------------------------------------------------------- /discussions/d4_hof/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 4 - Friday, February 24th 2 | 3 | ## Reminders 4 | 1. Project 2a due February 26th 11:59PM 5 | 2. Quiz 2 **date moved** to next Friday, March 3rd in discussion (see [Piazza](https://piazza.com/class/lctd1gtoyd76m8/post/801) for details) 6 | 7 | ## Introduction 8 | 9 | Today, we'll be covering `map` and `fold`, as well as an example of a custom data type. 10 | 11 | ## Part 1: Map 12 | 13 | Suppose you have a list in which you want to add one to each element. You could easily write a function to do this: 14 | 15 | ```ocaml 16 | let rec add1 xs = 17 | match xs with 18 | [] -> [] 19 | | h::t -> (h+1)::(add1 t) 20 | ;; 21 | ``` 22 | 23 | Now, let's consider a function that squares each element in a list: 24 | 25 | ```ocaml 26 | let rec square xs = 27 | match xs with 28 | [] -> [] 29 | | h::t -> (h*h)::(square t) 30 | ;; 31 | ``` 32 | 33 | Notice that both of these functions are *essentially* doing the same thing; they are performing the same task to each element of a list. We can generalize for any function `f` by using `map`. 34 | 35 | ```ocaml 36 | let rec map f xs = 37 | match xs with 38 | [] -> [] 39 | | h::t -> (f h)::(map f t) 40 | ;; 41 | ``` 42 | 43 | ## Part 2: Fold 44 | 45 | Suppose you want to compute the sum of each element in a list. We can write a function that does this: 46 | 47 | ```ocaml 48 | let rec sum xs = 49 | match xs with 50 | [] -> 0 51 | | h::t -> h+(sum t) 52 | ;; 53 | ``` 54 | 55 | What if you want to compute the size of a list? 56 | 57 | ```ocaml 58 | let rec size xs = 59 | match xs with 60 | [] -> 0 61 | | h::t -> 1+(size t) 62 | ;; 63 | ``` 64 | 65 | In each case, we are keeping track of an *accumulator* and adding onto it based on some property of the current element. We can generalize this to any function `f` using `fold` (also known as `fold_left`) and `fold_right`: 66 | 67 | ```ocaml 68 | let rec fold f a lst = 69 | match lst with 70 | []->a 71 | |h::t->fold f (f a h) t 72 | ;; 73 | 74 | let rec fold_right f lst a = 75 | match lst with 76 | []->a 77 | |h::t-> f h (fold_right f t a) 78 | ;; 79 | ``` 80 | 81 | A key difference between these two is the order of association. Consider the example of adding all elements of the list `[1;2;3;4]`. `fold_left` will associate from the left as follows: 82 | 83 | `(((0 + 1) + 2) + 3) + 4` 84 | 85 | On the other hand, `fold_right` will associate from the right as follows: 86 | 87 | `1 + (2 + (3 + (4 + 0)))` 88 | 89 | Notice how we assume that our accumulator starts with 0. 90 | 91 | ## Part 3: Tree Type 92 | 93 | To get more practice with pattern matching, custom data types and map/fold, let's build a `tree` data type! 94 | 95 | First, we will define the `tree` type: 96 | 97 | ```ocaml 98 | type 'a tree = 99 | | Leaf 100 | | Node of 'a tree * 'a * 'a tree 101 | ``` 102 | 103 | This recursively defines a `tree` to either be a 104 | - `Leaf` 105 | - `Node` with a left sub-`tree`, a value, and a right sub-`tree` 106 | 107 | Let's generalize `map` and `fold` to work on this `tree`. Try to implement it on your own! Can you describe the what the type of these functions should be? 108 | 109 | To practice with this, let's write a few functions using map and fold define on trees: 110 | 111 | - Write a function to return a `tree` with each value incremented by one: 112 | 113 | - Write a function to return the sum of all the elements of a `tree`: 114 | -------------------------------------------------------------------------------- /discussions/d4_hof/d4_skeleton.ml: -------------------------------------------------------------------------------- 1 | 2 | 3 | type 'a tree = 4 | | Leaf 5 | | Node of 'a tree * 'a * 'a tree 6 | 7 | let rec map f xs = 8 | match xs with 9 | [] -> [] 10 | | h::t -> (f h)::(map f t) 11 | 12 | let rec fold f a lst = 13 | match lst with 14 | []->a 15 | |h::t->fold f (f a h) t 16 | 17 | let rec fold_right f lst a = 18 | match lst with 19 | []->a 20 | |h::t-> f h (fold_right f t a) 21 | 22 | let rec map_tree f t = failwith "unimplemented" 23 | 24 | let rec fold_tree f b t = failwith "unimplemented" 25 | 26 | let add1 tree = failwith "unimplemented" 27 | 28 | let sum tree = failwith "unimplemented" -------------------------------------------------------------------------------- /discussions/d4_hof/d4_sol.ml: -------------------------------------------------------------------------------- 1 | type 'a tree = 2 | | Leaf 3 | | Node of 'a tree * 'a * 'a tree 4 | 5 | let rec map f xs = 6 | match xs with 7 | [] -> [] 8 | | h::t -> (f h)::(map f t) 9 | 10 | let rec fold f a lst = 11 | match lst with 12 | []->a 13 | |h::t->fold f (f a h) t 14 | 15 | let rec fold_right f lst a = 16 | match lst with 17 | []->a 18 | |h::t-> f h (fold_right f t a) 19 | 20 | let rec map_tree f t = 21 | match t with 22 | | Leaf -> Leaf 23 | | Node (l, v, r) -> let new_l = map_tree f l in 24 | let new_r = map_tree f r in 25 | Node (new_l, f v, new_r) 26 | 27 | 28 | let rec fold_tree f b t = 29 | match t with 30 | | Leaf -> b 31 | | Node (l, v, r) -> let res_l = fold_tree f b l in 32 | let res_r = fold_tree f b r in 33 | f res_l v res_r 34 | 35 | 36 | let add1 tree = map_tree (fun x -> x + 1) tree 37 | 38 | let sum tree = fold_tree (fun x l r -> x + l + r) 0 tree 39 | 40 | let test_tree = Node(Node(Leaf, 4, Leaf), 5, Node(Leaf, 2, Leaf)) ;; 41 | 42 | sum test_tree;; 43 | 44 | let test2 = add1 test_tree;; -------------------------------------------------------------------------------- /discussions/d5_project_review/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 5 - Friday, March 3rd 2 | 3 | ## Reminders 4 | 1. Quiz 2 is **today** March 3rd 5 | 2. Project 2b due March 12th 11:59PM 6 | 3. Exam 1 is coming up on March 14th 7 | 8 | Today, we will be briefly discussing how to evaluate a subset of the `condition`s from Project 2b. 9 | 10 | ```ml 11 | type condition = 12 | | True 13 | | False 14 | | And of condition * condition 15 | | Or of condition * condition 16 | | Not of condition 17 | | If of condition * condition * condition 18 | ``` 19 | Notice how this definition is recursive. The “base cases” are True and False, and the other conditions have conditions within them. Some examples of conditions are: 20 | - `Or(Not(True), False)` 21 | - `And(Or(True, Not(False))), True)` 22 | - `If(True, Or(True, False), And(False,Not(True)))` 23 | - `If(And(True, True), Or(Not(False), True), False)` 24 | 25 | To interpret these conditions, we can think of “unwrapping” the condition based on what type of condition it is. We can use pattern matching to implement this. 26 | 27 | ```ml 28 | let rec is_true condition = match condition with 29 | | True -> true 30 | | False -> false 31 | | And(x,y) -> (is_true x) && (is_true y) 32 | | Or(x,y) -> (is_true x) || (is_true y) 33 | | Not(x) -> not (is_true x) 34 | | If(x,y,z) -> if (is_true x) then (is_true y) else (is_true z) 35 | ``` 36 | -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 6 - Friday, March 10th 2 | 3 | ## Reminders 4 | 1. Project 2b due March 12th 11:59PM 5 | 2. Exam 1 is **next Tuesday** March 14th 6 | 3. Quiz 2 regrade requests open until March 16th 7 | 3. Quiz 3 is **next Friday in discussion** March 17th 8 | 9 | 10 | ## NFA and DFA 11 | ### Key Differences between NFA and DFA: 12 | - NFA can have ε-transition(s) between states. 13 | - NFA states can have multiple transitions going out of them using the same symbol. 14 | 15 | ### Formal Definition 16 | A DFA is a 5-tuple (Σ, Q, q0, F, δ) where 17 | - Σ is an alphabet 18 | - Q is a nonempty set of states 19 | - q0 ∈ Q is the start state 20 | - F ⊆ Q is the set of final states 21 | - δ : Q x Σ → Q specifies the DFA's transitions 22 | 23 | ### Review 24 | 25 | 1. What are some strings that would be accepted by this NFA? 26 | 27 | 28 | 29 | ## Converting from NFA to DFA 30 | 31 | Reducing NFA to DFA uses two subroutines: e-closure and move. 32 | 33 | ### ε-closure 34 | `ε-closure(δ, p)` returns the set of states reachable from p using ε-transitions alone. 35 | 36 | 37 | 38 | - ε-closure(p1) = { p1, p2, p3 } 39 | - ε-closure(p2) = { p2, p3 } 40 | - ε-closure(p3) = { p3 } 41 | - ε-closure( { p1, p2 } ) = { p1, p2, p3 } ∪ { p2, p3 } 42 | 43 | ### move 44 | `move(δ,p,σ)` returns the set of states reachable from p using exactly one transition on symbol σ. 45 | 46 | 47 | 48 | - move(p1, a) = { p2, p3 } 49 | - move(p1, b) = ∅ 50 | - move(p2, a) = ∅ 51 | - move(p2, b) = { p3 } 52 | - move(p3, a) = ∅ 53 | - move(p3, b) = ∅ 54 | - move( {p1, p2} , b) = { p3 } 55 | 56 | ### Algorithm 57 | Let $r_0$ = $\varepsilon\text{-closure}(\delta, q_0)$, add it to $R$\ 58 | While $\exists$ an unmarked state $r \in R$:\ 59 |       Mark $r$\ 60 |       For each $\sigma \in \Sigma$\ 61 |             Let $E = \text{move}(\delta, r, \sigma)$\ 62 |             Let $e = \varepsilon\text{-closure}(\delta, E)$\ 63 |             If $e \notin R$\ 64 |                   Let $R = R \cup \\{e\\}$\ 65 |             Let $\delta' = \delta \cup \\{ r, \sigma, e \\} $\ 66 | Let $F = \\{r \mid \exists s \in r \text{ with } s \in F_n \\}$ 67 | 68 | ### Practice 69 | Convert the following NFAs to their DFAs. 70 | 71 | ![nfa](nfa-accept.png) 72 | 73 | ![nfa](nfa2.png) 74 | 75 | -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/nfa-accept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d6_nfa_dfa/nfa-accept.png -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/nfa-e-closure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d6_nfa_dfa/nfa-e-closure.png -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/nfa-move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d6_nfa_dfa/nfa-move.png -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/nfa2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d6_nfa_dfa/nfa2.png -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/nfa_to_dfa_1_sol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d6_nfa_dfa/nfa_to_dfa_1_sol.jpg -------------------------------------------------------------------------------- /discussions/d6_nfa_dfa/nfa_to_dfa_2_sol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d6_nfa_dfa/nfa_to_dfa_2_sol.png -------------------------------------------------------------------------------- /discussions/d7_opsem/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 7 - Friday, March 17th 2 | 3 | ## Reminders 4 | 1. Project 3 is due on April 5th 5 | 2. Quiz 3 is **today!** 6 | 7 | ## Operational Semantics 8 | The whole idea behind "operational semantics" is trying to *systematically* understand how programs evaluate parsed expressions or statements. In other words, we want to be able to **prove** that our programs do indeed work correctly. We do this through the use of axioms and hypotheses to draw conclusions. 9 | 10 | ### Problem 1: 11 | image 12 | 13 | ### Problem 2: 14 | image 15 | -------------------------------------------------------------------------------- /discussions/d7_opsem/solutions/opsem1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d7_opsem/solutions/opsem1.png -------------------------------------------------------------------------------- /discussions/d7_opsem/solutions/opsem2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d7_opsem/solutions/opsem2.png -------------------------------------------------------------------------------- /discussions/d8_cfg/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 8 - Friday, March 31st 2 | 3 | ## Reminders 4 | 1. Project 3 is due on April 5th 5 | 2. Quiz 3 regrade requests open until April 7th 6 | 7 | ## Context Free Grammars 8 | 9 | image 10 | 11 | ### Practicing Derivations 12 | Grammar: S -> S + S | 1 | 2 | 3 13 | 14 | Leftmost derivation of 1 + 2 + 3 15 | * Start with S and use the production rules on the LEFTMOST nonterminal ONE AT A TIME. (For a rightmost derivation, use the productions on the RIGHTMOST nonterminal.) 16 | * ONE NONTERMINAL AT A TIME!!!! DON'T COMBINE STEPS!!!! 17 | * S -> S + S -> S + S + S -> 1 + S + S -> 1 + 2 + S -> 1 + 2 + 3 18 | * S -> S + S -> 1 + S -> 1 + S + S -> 1 + 2 + S -> 1 + 2 + 3 works too 19 | 20 | Note: If there are 2 leftmost derivations or 2 rightmost for the same string, what does that mean? The grammar is ambiguous. 21 | * To show that a grammar is ambiguous, show 2 different leftmost or rightmost derivations for the same string. 22 | * You must give 2 leftmost or 2 rightmost derevations, not one leftmost and one rightmost 23 | * It's hard to know whether a grammar is ambiguous or not, but be suspicious if you see something along the lines of S -> SS, S -> SSS, S -> S+S, etc. 24 | 25 | ### More CFG Practice 26 | Given the following grammar: 27 | 28 | S -> aS | T
29 | T -> bT | U
30 | U -> cU | ε
31 | 32 | Provide derivations for: 33 | * b 34 | * ac 35 | * bbc 36 | 37 | What language is accepted by this grammar? 38 | 39 | Create another grammar that accepts the same language. 40 | 41 | ### Parsing Practice (Drawing ASTs) 42 | Given the string "(4 + (5 * (6 + 7)))" and the grammar below, draw the corresponding AST. 43 | 44 | S -> M + S | M 45 | 46 | M -> N * M | N 47 | 48 | N -> n | (S) 49 | 50 | where n is any integer 51 | -------------------------------------------------------------------------------- /discussions/d9_parsing/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d9_parsing/.DS_Store -------------------------------------------------------------------------------- /discussions/d9_parsing/README.md: -------------------------------------------------------------------------------- 1 | # Discussion 9 - Friday, April 7th 2 | 3 | ## Reminders 4 | * Quiz 4 is next week! 5 | * Exam 2 is on 4/20 6 | 7 | ## Coding Exercise 8 | * To go from source code to a running program, there are 3 steps (at least for our purposes): 9 | * Tokenizing/Lexing (separating text into smaller tokens) 10 | * Parsing (generating something meaningful from the tokens - an AST) 11 | * Interpreting (evaluating the result of the AST) 12 | 13 | * Consider the following grammar: 14 | * S -> M + S | M 15 | * M -> N * M | N 16 | * N -> n | (S) 17 | * where n is any integer 18 | 19 | * This grammar is right associative/recursive (Why did we provide a right associative grammar? What would you do if we didn't?). 20 | 21 | * What is the relative precedence of the + and \* operators here? How is it determined? How can we use CFGs to enforce precedence? 22 | 23 | ### Lexer 24 | * Open `lexer.skeleton.ml`. 25 | * Answer key in `lexer.ml` 26 | * Note the variant type `token` we have defined. 27 | * Keep an index that keeps track of where we are in the string, and move forward as we keep tokenizing. 28 | * In P4, you will have to worry about the order in which you have `if/else` ... `if/else` statements (certain regexs should be checked before others). 29 | * It's probably also a good idea to just define all the regex's and store in variables at the top. 30 | 31 | ### Parser 32 | * Open `parser.skeleton.ml`. 33 | * Answer key in `parser.ml` (will be uploaded after discussion) 34 | * Note the variant type `expr` that we have defined 35 | * Note: Use `let rec ...` and to write mutually recursive functions. 36 | * Note: `lookahead` just returns the head of the list. 37 | * Note: `match` just "consumes" the head of the list (provided that the token and head of the list match). 38 | * IMPORTANT: 39 | * We're going to write a function named `parse_X` for each nonterminal `X` in our grammar. 40 | * Each of these functions will parse (consume) some tokens, and return (1) the unparsed tokens and (2) the AST which corresponds to the parsed tokens. 41 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/discussions/d9_parsing/src/.DS_Store -------------------------------------------------------------------------------- /discussions/d9_parsing/src/interpreter.ml: -------------------------------------------------------------------------------- 1 | open Parser 2 | 3 | (* Evaluater *) 4 | 5 | let rec eval (ast : expr) : int = 6 | match ast with 7 | | Int x -> x 8 | | Mult (x, y) -> let x' = eval x in 9 | let y' = eval y in 10 | x' * y' 11 | | Plus (x, y) -> let x' = eval x in 12 | let y' = eval y in 13 | x' + y' 14 | 15 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/interpreter.mli: -------------------------------------------------------------------------------- 1 | val eval : Parser.expr -> int 2 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/interpreter.skeleton.ml: -------------------------------------------------------------------------------- 1 | open Parser 2 | 3 | (* Evaluater *) 4 | 5 | let rec eval (ast : expr) : int = 6 | failwith "unimplemented" 7 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/lexer.ml: -------------------------------------------------------------------------------- 1 | (*#load "str.cma";;*) 2 | 3 | (* Type *) 4 | type token = 5 | | Tok_Int of int 6 | | Tok_Mult 7 | | Tok_Plus 8 | | Tok_LParen 9 | | Tok_RParen 10 | | Tok_EOF 11 | 12 | let string_of_token tok = match tok with 13 | | Tok_Int(i) -> string_of_int i 14 | | Tok_Mult -> "*" 15 | | Tok_Plus -> "+" 16 | | Tok_LParen -> "(" 17 | | Tok_RParen -> ")" 18 | | Tok_EOF -> "" 19 | 20 | 21 | let rec string_of_list conv lst = 22 | match lst with 23 | | [] -> "" 24 | | h::[] -> conv h 25 | | h::t -> (conv h) ^ " " ^ (string_of_list conv t) 26 | 27 | (* Given source code returns a token list. *) 28 | let rec lexer (input : string) : token list = 29 | let length = String.length input in 30 | 31 | let rec tok pos = 32 | if pos >= length then 33 | [Tok_EOF] 34 | 35 | else if Str.string_match (Str.regexp "(") input pos then 36 | Tok_LParen::(tok (pos + 1)) 37 | 38 | else if Str.string_match (Str.regexp ")") input pos then 39 | Tok_RParen::(tok (pos + 1)) 40 | 41 | else if Str.string_match (Str.regexp "\\+") input pos then 42 | Tok_Plus::(tok (pos + 1)) 43 | 44 | else if Str.string_match (Str.regexp "\\*") input pos then 45 | Tok_Mult::(tok (pos + 1)) 46 | 47 | else if Str.string_match (Str.regexp "-?[0-9]+") input pos then 48 | let value = Str.matched_string input in 49 | Tok_Int(int_of_string value)::(tok (pos + String.length value)) 50 | 51 | else 52 | tok (pos + 1) 53 | 54 | in tok 0;; 55 | 56 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/lexer.mli: -------------------------------------------------------------------------------- 1 | type token = 2 | | Tok_Int of int 3 | | Tok_Mult 4 | | Tok_Plus 5 | | Tok_LParen 6 | | Tok_RParen 7 | | Tok_EOF 8 | 9 | val lexer : string -> token list 10 | 11 | val string_of_token : token -> string 12 | 13 | val string_of_list : ('a -> string) -> 'a list -> string 14 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/lexer.skeleton.ml: -------------------------------------------------------------------------------- 1 | (* Type *) 2 | type token = 3 | | Tok_Int of int 4 | | Tok_Mult 5 | | Tok_Plus 6 | | Tok_LParen 7 | | Tok_RParen 8 | | Tok_EOF 9 | 10 | let string_of_token tok = match tok with 11 | | Tok_Int(i) -> string_of_int i 12 | | Tok_Mult -> "*" 13 | | Tok_Plus -> "+" 14 | | Tok_LParen -> "(" 15 | | Tok_RParen -> ")" 16 | | Tok_EOF -> "" 17 | 18 | let rec string_of_list conv lst = 19 | match lst with 20 | | [] -> "" 21 | | h::[] -> conv h 22 | | h::t -> (conv h) ^ " " ^ (string_of_list conv t) 23 | 24 | (* Given source code returns a token list. *) 25 | let rec lexer (input : string) : token list = 26 | failwith "unimplemented" 27 | 28 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/parser.ml: -------------------------------------------------------------------------------- 1 | open Lexer 2 | 3 | (* Types *) 4 | type expr = 5 | | Int of int 6 | | Plus of expr * expr 7 | | Mult of expr * expr 8 | 9 | (* Provided helper function - takes a token list and an exprected token. 10 | * Handles error cases and returns the tail of the list *) 11 | let match_token (toks : token list) (tok : token) : token list = 12 | match toks with 13 | | [] -> raise (Failure(string_of_token tok)) 14 | | h::t when h = tok -> t 15 | | h::_ -> raise (Failure( 16 | Printf.sprintf "Expected %s from input %s, got %s" 17 | (string_of_token tok) 18 | (string_of_list string_of_token toks) 19 | (string_of_token h) 20 | )) 21 | 22 | let lookahead toks = match toks with 23 | h::t -> h 24 | | _ -> raise (Failure("Empty input to lookahead")) 25 | 26 | 27 | (* Parses a token list. *) 28 | let rec parser (toks : token list) : expr = 29 | let (t, exp) = parse_S toks in 30 | if t <> [Tok_EOF] then 31 | raise (Failure "did not reach EOF") 32 | else 33 | exp 34 | 35 | (* Parses the S rule. *) 36 | and parse_S toks = 37 | let (t, m) = parse_M toks in 38 | match lookahead t with 39 | | Tok_Plus -> let t' = match_token t Tok_Plus in 40 | let (t'', s) = parse_S t' in 41 | (t'', Plus (m, s)) 42 | | _ -> t, m 43 | 44 | (* Parses the M rule. *) 45 | and parse_M toks = 46 | let (t, n) = parse_N toks in 47 | match lookahead t with 48 | | Tok_Mult -> let t' = match_token t Tok_Mult in 49 | let (t'', m) = parse_M t' in 50 | (t'', Mult (n, m)) 51 | | _ -> t, n 52 | 53 | (* Parses the N rule. *) 54 | and parse_N toks = 55 | match lookahead toks with 56 | | Tok_Int i -> let t = match_token toks (Tok_Int i) in 57 | (t, Int i) 58 | | Tok_LParen -> let t = match_token toks Tok_LParen in 59 | let (t', s) = parse_S t in 60 | let t'' = match_token t' Tok_RParen in 61 | (t'', s) 62 | | _ -> failwith "parse_N failed" 63 | -------------------------------------------------------------------------------- /discussions/d9_parsing/src/parser.mli: -------------------------------------------------------------------------------- 1 | type expr = 2 | | Int of int 3 | | Plus of expr * expr 4 | | Mult of expr * expr 5 | 6 | val parser : Lexer.token list -> expr 7 | val parse_S : Lexer.token list -> Lexer.token list * expr 8 | val parse_M : Lexer.token list -> Lexer.token list * expr 9 | val parse_N : Lexer.token list -> Lexer.token list * expr -------------------------------------------------------------------------------- /discussions/d9_parsing/src/parser.skeleton.ml: -------------------------------------------------------------------------------- 1 | open Lexer 2 | 3 | (* Types *) 4 | type expr = 5 | | Int of int 6 | | Plus of expr * expr 7 | | Mult of expr * expr 8 | 9 | (* Provided helper function - takes a token list and an exprected token. 10 | * Handles error cases and returns the tail of the list *) 11 | let match_token (toks : token list) (tok : token) : token list = 12 | match toks with 13 | | [] -> raise (Failure(string_of_token tok)) 14 | | h::t when h = tok -> t 15 | | h::_ -> raise (Failure( 16 | Printf.sprintf "Expected %s from input %s, got %s" 17 | (string_of_token tok) 18 | (string_of_list string_of_token toks) 19 | (string_of_token h) 20 | )) 21 | 22 | let lookahead toks = match toks with 23 | h::t -> h 24 | | _ -> raise (Failure("Empty input to lookahead")) 25 | 26 | 27 | 28 | (* Parses a token list. *) 29 | let rec parser (toks : token list) : expr = 30 | failwith "unimplemented" 31 | 32 | (* Parses the S rule. *) 33 | and parse_S (toks : token list) : (token list * expr) = 34 | failwith "unimplemented" 35 | 36 | (* Parses the M rule. *) 37 | and parse_M (toks : token list) : (token list * expr) = 38 | failwith "unimplemented" 39 | 40 | (* Parses the N rule. *) 41 | and parse_N (toks : token list) : (token list * expr) = 42 | failwith "unimplemented" 43 | -------------------------------------------------------------------------------- /lecture_code/math-ew/input.txt: -------------------------------------------------------------------------------- 1 | ^ 2 sq 3 2 | => 9 3 | E -> n 4 | |+ E E 5 | |* E E 6 | |/ E E 7 | |- E E 8 | |^ E E 9 | |sq E 10 | 11 | e1 -> v1 e2 -> v2 v3 is v1 ^ v2 12 | ---------------------------------- 13 | ^ e1 e2 -> v3 14 | 15 | e1 -> v1 e2 -> v2 v3 is v1 + v2 16 | ---------------------------------- 17 | + e1 e2 -> v3 18 | 19 | e1 -> v1 e2 -> v2 v3 is v1 / v2 20 | ---------------------------------- 21 | / e1 e2 -> v3 22 | 23 | lexer: string -> token list 24 | do all the words exist in the lexicon 25 | valid: 26 | the person ran fast, person the fast ran 27 | invlid: the sdfj truck 28 | 29 | parser: token list -> ast 30 | is sentence grammatically correct 31 | valid: 32 | the boy ran fast, the large red truck 33 | invalid: 34 | ran fast the boy, the truck red 35 | 36 | evaluator: ast -> value 37 | does it makes sense 38 | valid: the boy ran fast 39 | invalid: 40 | colorless green ideas sleep furiously 41 | -------------------------------------------------------------------------------- /lecture_code/math-ew/lec1.rb: -------------------------------------------------------------------------------- 1 | f = File.open("input.txt") 2 | line = f.gets 3 | line.chomp! 4 | 5 | def lex(line) 6 | number = /^(-?\d+)/ 7 | plus = /^\+/ 8 | sub = /^-/ 9 | mult = /^\*/ 10 | div = /^\// 11 | exp = /^\^/ 12 | sq = /^sq/ 13 | wspace = /^ / 14 | 15 | tokens = [] 16 | while line.length > 0 17 | if line =~ number 18 | tokens.push(["int",$1]) 19 | line = line[$1.length..] 20 | elsif line =~ wspace 21 | line = line[1..] 22 | elsif line =~ plus 23 | tokens.push("plus") 24 | line = line[1..] 25 | elsif line =~ sub 26 | tokens.push("sub") 27 | line = line[1..] 28 | elsif line =~ mult 29 | tokens.push("mult") 30 | line = line[1..] 31 | elsif line =~ div 32 | tokens.push("div") 33 | line = line[1..] 34 | elsif line =~ exp 35 | tokens.push("exp") 36 | line = line[1..] 37 | elsif line =~ sq 38 | tokens.push("sq") 39 | line = line[2..] 40 | else 41 | raise IOError.new("unknown symbol") 42 | end 43 | end 44 | tokens 45 | end 46 | 47 | lexed = lex(line) 48 | #puts lexed.to_s 49 | 50 | def parser(tokens) 51 | parsed,leftover = parser2(tokens) 52 | if leftover == [] or leftover == nil 53 | return parsed 54 | else 55 | raise IOError.new("Gramatically incorrect") 56 | end 57 | end 58 | 59 | def parser2(tokens) #token -> tree,leftover 60 | tree = [] 61 | if tokens == nil or tokens == [] 62 | raise IOError.new("Gramatically incorrect") 63 | end 64 | curr = tokens[0] 65 | if curr == "plus" 66 | op = "plus" 67 | rest = tokens[1..] 68 | e1,leftover = parser2(rest) 69 | e2,leftover = parser2(leftover) 70 | return [op,e1,e2],leftover 71 | elsif curr == "mult" 72 | op = "mult" 73 | rest = tokens[1..] 74 | e1,leftover = parser2(rest) 75 | e2,leftover = parser2(leftover) 76 | return [op,e1,e2],leftover 77 | elsif curr == "sub" 78 | op = "sub" 79 | rest = tokens[1..] 80 | e1,leftover = parser2(rest) 81 | e2,leftover = parser2(leftover) 82 | return [op,e1,e2],leftover 83 | elsif curr == "div" 84 | op = "div" 85 | rest = tokens[1..] 86 | e1,leftover = parser2(rest) 87 | e2,leftover = parser2(leftover) 88 | return [op,e1,e2],leftover 89 | elsif curr == "exp" 90 | op = "exp" 91 | rest = tokens[1..] 92 | e1,leftover = parser2(rest) 93 | e2,leftover = parser2(leftover) 94 | return [op,e1,e2],leftover 95 | elsif curr == "sq" 96 | op = "sq" 97 | rest = tokens[1..] 98 | e1,leftover = parser2(rest) 99 | return [op,e1],leftover 100 | elsif curr.class == Array 101 | int = curr[1] 102 | rest = tokens[1..] 103 | return [int],rest 104 | else 105 | raise IOError.new("Gramatically incorrect") 106 | end 107 | end 108 | 109 | parsed = parser(lexed) 110 | puts parsed.to_s 111 | 112 | def evaluate(tree) 113 | curr = tree 114 | if curr.length == 1 115 | return curr[0].to_i 116 | elsif curr.length == 2 117 | op = curr[0] 118 | child = curr[1] 119 | e1 = evaluate(child) 120 | if op == "sq" 121 | return e1 * e1 122 | else 123 | raise IOError.new("Something wrong") 124 | end 125 | else 126 | op = curr[0] 127 | left = curr[1] 128 | right = curr[2] 129 | e1 = evaluate(left) 130 | e2 = evaluate(right) 131 | if op == "plus" 132 | return e1 + e2 133 | elsif op == "div" 134 | return e1 / e2 135 | elsif op == "mult" 136 | return e1 * e2 137 | elsif op == "sub" 138 | return e1 - e2 139 | elsif op == "exp" 140 | return e1 ** e2 141 | else 142 | raise IOError.new("does not make sense") 143 | end 144 | end 145 | end 146 | #puts parsed.to_s 147 | value = evaluate(parsed) 148 | puts value 149 | -------------------------------------------------------------------------------- /lecture_code/math-ew/lec2.rb: -------------------------------------------------------------------------------- 1 | f = File.open("input.txt") 2 | line = f.gets 3 | line = line.chomp 4 | 5 | def lex(line) 6 | number = /^(-?\d+)/ 7 | plus = /^\+/ 8 | sub = /^-/ 9 | mult = /^\*/ 10 | div = /^\// 11 | exp = /^\^/ 12 | sq = /^sq/ 13 | wspace = /^ / 14 | 15 | tokens = [] 16 | 17 | while line.length > 0 18 | if line =~ number 19 | tokens.push(["int",$1]) 20 | line = line[$1.length..] 21 | elsif line =~ wspace 22 | line = line[1..] 23 | elsif line =~ plus 24 | tokens.push("plus") 25 | line = line[1..] 26 | elsif line =~ div 27 | tokens.push("div") 28 | line = line[1..] 29 | elsif line =~sub 30 | tokens.push("sub") 31 | line = line[1..] 32 | elsif line =~ mult 33 | tokens.push("mult") 34 | line = line[1..] 35 | elsif line =~ exp 36 | tokens.push("exp") 37 | line = line[1..] 38 | elsif line =~ sq 39 | tokens.push("sq") 40 | line = line[2..] 41 | else 42 | raise IOError.new("unknown symbol") 43 | end 44 | end 45 | tokens 46 | end 47 | 48 | 49 | def parser(tokens) 50 | tree,leftover = parser2(tokens) 51 | if leftover == nil or leftover == [] 52 | return tree 53 | else 54 | raise IOError.new("Grammatically invalid") 55 | end 56 | end 57 | 58 | def parser2(tokens) 59 | if tokens == [] or tokens == nil 60 | raise IOError.new("grammatically invalid") 61 | end 62 | curr = tokens[0] 63 | if curr == "plus" 64 | op = "plus" 65 | rest = tokens[1..] 66 | e1,leftover = parser2(rest) 67 | e2,leftover = parser2(leftover) 68 | return [op,e1,e2],leftover 69 | elsif curr == "sub" 70 | op = "sub" 71 | rest = tokens[1..] 72 | e1,leftover = parser2(rest) 73 | e2,leftover = parser2(leftover) 74 | return [op,e1,e2],leftover 75 | elsif curr == "mult" 76 | op = "mult" 77 | rest = tokens[1..] 78 | e1,leftover = parser2(rest) 79 | e2,leftover = parser2(leftover) 80 | return [op,e1,e2],leftover 81 | elsif curr == "div" 82 | op = "div" 83 | rest = tokens[1..] 84 | e1,leftover = parser2(rest) 85 | e2,leftover = parser2(leftover) 86 | return [op,e1,e2],leftover 87 | elsif curr == "exp" 88 | op = "exp" 89 | rest = tokens[1..] 90 | e1,leftover = parser2(rest) 91 | e2,leftover = parser2(leftover) 92 | return [op,e1,e2],leftover 93 | elsif curr == "sq" 94 | op = "sq" 95 | rest = tokens[1..] 96 | e1,leftover = parser2(rest) 97 | return [op,e1],leftover 98 | elsif curr.class == Array 99 | int = curr[1] 100 | rest = tokens[1..] 101 | return [int],rest 102 | else 103 | raise IOError.new("grammatically incorrect") 104 | end 105 | end 106 | 107 | def interp(tree) 108 | curr = tree 109 | if curr.length == 3 110 | op = curr[0] 111 | v1 = interp curr[1] 112 | v2 = interp curr[2] 113 | if op == "plus" 114 | return v1 + v2 115 | elsif op == "sub" 116 | return v1 - v2 117 | elsif op == "mult" 118 | return v1 * v2 119 | elsif op == "div" 120 | return v1 / v2 121 | elsif op == "exp" 122 | return v1 ** v2 123 | else 124 | raise IOError.new("does not make sense") 125 | end 126 | elsif curr.length == 1 127 | return curr[0].to_i 128 | elsif curr.length == 2 129 | op = curr[0] 130 | if op == "sq" 131 | v1 = interp curr[1] 132 | return v1 * v1 133 | else 134 | raise IOError.new("does not make sense") 135 | end 136 | else 137 | raise IOError.new("does not make sense") 138 | end 139 | end 140 | 141 | 142 | lexed = lex(line) 143 | puts lexed.to_s 144 | parsed = parser(lexed) 145 | puts parsed.to_s 146 | value = interp(parsed) 147 | puts value 148 | -------------------------------------------------------------------------------- /lecture_code/math-ew/lec3.rb: -------------------------------------------------------------------------------- 1 | f = File.open("input.txt") 2 | line = f.gets 3 | line = line.chomp 4 | 5 | def lex(line) 6 | number = /^(-?\d+)/ 7 | plus = /^\+/ 8 | mult = /^\*/ 9 | sub = /^-/ 10 | div = /^\// 11 | exp = /^\^/ 12 | sq = /^sq/ 13 | wspace = /^ / 14 | 15 | token = [] 16 | 17 | while line.length > 0 18 | if line =~ number 19 | token.push(["int",$1]) 20 | line = line[$1.length..] 21 | elsif line =~ wspace 22 | line = line[1..] 23 | elsif line =~ plus 24 | token.push("plus") 25 | line = line[1..] 26 | elsif line =~ sub 27 | token.push("sub") 28 | line = line[1..] 29 | elsif line =~ mult 30 | token.push("mult") 31 | line = line[1..] 32 | elsif line =~ div 33 | token.push("div") 34 | line = line[1..] 35 | elsif line =~ exp 36 | token.push("exp") 37 | line = line[1..] 38 | elsif line =~ sq 39 | token.push("sq") 40 | line = line[2..] 41 | else 42 | raise IOError.new("Character not allowed") 43 | end 44 | end 45 | token 46 | end 47 | 48 | def parser(tokens) 49 | tree,leftover = parser2(tokens) 50 | if leftover.length > 0 then 51 | raise IOError.new("grammatically incorrect") 52 | end 53 | return tree 54 | end 55 | 56 | def parser2(tokens) 57 | #[op,e1,e2] 58 | #[op,e1] 59 | #[n] 60 | if tokens == nil or tokens == [] 61 | raise IOError.new("Grammatically invliad") 62 | end 63 | curr = tokens[0] 64 | rest = tokens[1..] 65 | if curr == "plus" or curr == "sub" or curr == "mult" or curr == "div" or curr == "exp" 66 | node = [curr] 67 | e1,leftover = parser2(rest) 68 | e2,leftover = parser2(leftover) 69 | node.push(e1) 70 | node.push(e2) 71 | return node,leftover 72 | elsif curr == "sq" 73 | node = [curr] 74 | e1,leftover = parser2(rest) 75 | node.push(e1) 76 | return node,leftover 77 | elsif curr.class == Array 78 | if curr[0] == "int" 79 | int = curr[1].to_i 80 | return [int],rest 81 | else 82 | raise IOError.new("grammatically wrong") 83 | end 84 | else 85 | raise IOError.new("grammatically wrong") 86 | end 87 | end 88 | 89 | def evaluator(tree) 90 | if tree.length == 3 91 | op = tree[0] 92 | v1 = evaluator(tree[1]) 93 | v2 = evaluator(tree[2]) 94 | if op == "plus" 95 | return v1 + v2 96 | elsif op == "sub" 97 | return v1 - v2 98 | elsif op == "mult" 99 | return v1 * v2 100 | elsif op == "div" 101 | return v1 / v2 102 | elsif op == "exp" 103 | return v1 ** v2 104 | else 105 | raise IOError.new("Makes no sense") 106 | end 107 | elsif tree.length == 2 108 | op = tree[0] 109 | v1 = evaluator(tree[1]) 110 | if op == "sq" 111 | return v1 * v1 112 | else 113 | raise IOError.new("makes no sense") 114 | end 115 | elsif tree.length == 1 116 | return tree[0] 117 | else 118 | raise IOError.new("Makes no sense") 119 | end 120 | end 121 | 122 | lexed = lex(line) 123 | puts lexed.to_s 124 | parsed = parser(lexed) 125 | puts parsed.to_s 126 | value = evaluator(parsed) 127 | puts value 128 | -------------------------------------------------------------------------------- /lecture_code/may4/lec1.txt: -------------------------------------------------------------------------------- 1 | struct Rectangle{ 2 | height:u32, 3 | width:u32, 4 | } 5 | 6 | struct Circle{ 7 | radius:f32; 8 | circum:f64; 9 | } 10 | struct Shape{ 11 | r:Rectangle, 12 | c:Circle, 13 | } 14 | 15 | impl Rectangle{ 16 | fn area(&self)->u64{ 17 | self.height * self.width 18 | } 19 | } 20 | 21 | impl Circle{ 22 | fn area(&self) -> f64{ 23 | self.radius * self.radius * 3.14 24 | } 25 | } 26 | 27 | let r1 = Rectangle{width:5,height:10,}; 28 | let a = r1.area(); 29 | println!("{}",a); 30 | 31 | pub trait polygon{ 32 | fn perimeter(&self) -> u32{ 33 | -1 34 | } 35 | } 36 | 37 | impl polygon for Rectangle{ 38 | fn perimeter(&self)-> u32{ 39 | self.height * 2 + self.width * 2 40 | } 41 | } 42 | 43 | impl polygon for Circle{ 44 | fn perimeter(&self) -> u32{ 45 | self.circum as u32 46 | } 47 | } 48 | 49 | objects has methods 50 | method: a function that is associated with a partcular object 51 | 52 | drop 53 | copy 54 | clone 55 | 56 | let x = 5; 57 | 58 | for i in [1,2,3,4] 59 | puts i 60 | 61 | 62 | for value in arr{ 63 | println!("{}",value); 64 | } 65 | 66 | type i = a.iterator() 67 | 68 | while i.hasNext(){ 69 | i.next() 70 | } 71 | 72 | reference: similar to a c pointer 73 | 74 | free(x); 75 | ... 76 | free(x); 77 | 78 | when the owner goes out of scope, the value is dropped (free) 79 | let mut x = String::from("hello") 80 | // x is a mutable reference to the value hello 81 | { 82 | let y = &x; 83 | //y is a immutable refence to the value hello 84 | //we cannot have both a mutable reference and an immutable ref, so x is now immutable 85 | println!("{}",y,x); 86 | }// y goes out of scope, so the immutable reference is "dropped", and so x goes back to being 87 | //mutable 88 | 89 | x.push_str("world"); 90 | 91 | println!("{}",x); 92 | 93 | so x is still the owner here, but y now has a immutable reference to the value x owns 94 | 95 | 96 | 97 | let mut x = String::from("hello") 98 | // x is a mutable reference to the value hello 99 | { 100 | let y = &mut x; 101 | //y is a mutable refence to the value hello 102 | // we cannot have more than one mutable reference so x becomes invalid for as long as y exists 103 | println!("{}",y); 104 | }// y goes out of scope, so now x becomes valid again 105 | 106 | x.push_str("world"); 107 | 108 | println!("{}",x); 109 | 110 | 111 | 112 | 1 let x = 4; //x is created so it's lifetime begins 113 | 2 let y = 3; // 114 | 3 let z = x + y; 115 | 4 println!("{}", z); 116 | 5 println!("{}", y); 117 | 6 println!("{}", x); //x is last used so it's lifetime ends 118 | 119 | x:'a 120 | rust treats lifetime as extension of type 121 | 122 | 3:int 123 | 4.0:float 124 | 125 | x:isize for the lifetime of 'a 126 | y:f32 for the lifetime of 'b 127 | 128 | fn foo(a:&'a int) -> &'a int{ 129 | 130 | } 131 | 132 | fn foo(a:&u32) -> &String{ 133 | 134 | } 135 | 136 | 1) rust will add a different lifetime to all input parameters that are a reference 137 | 2) if one lifetime parameter, then output has the same 138 | 3) if multiple inputs AND one is self or &self, then lifetime of output is same as self or &self 139 | 140 | fn bar(x:&'a u32, y:&'b u32) -> &'? u32{ 141 | 142 | } 143 | 144 | fn bar(x:&'a u32, y:&'b u32) -> &'a u32{ 145 | 146 | } 147 | out input lifetimes are dependent on output lifetimes 148 | 149 | we want to avoid dangling pointers 150 | lifetime of return value is at maximum th lifetime of the input it's linked to 151 | 152 | 153 | let f x = x + 1; ocaml does typie inference 154 | 155 | rust does lifetime inference 156 | 157 | 158 | explict lifetime parameters do not change the actual lifetime of anything 159 | all it does is help the rust compiler compiler know, when it should expect things to life 160 | 161 | 162 | 163 | 164 | 165 | 166 | lambda calc 167 | what is a beta reduction 168 | call by name vs call by value 169 | then particular cases 170 | 171 | e -> x 172 | |(Lx.e) 173 | |e1 e2 174 | 175 | (Lx.x y) a 176 | --e1--- -e2- 177 | 178 | beta reduction: call the function/apply the left value (e1) to the function on the right (e2) 179 | if left valuu (e1) is not function, then we cannot beta reduce hence, we are in beta normal form 180 | 181 | call by name and call by value are rules of precedence as to what to beta reduce first 182 | 183 | (Lx.Ly.y)((La.a a) b) 184 | -------- -------- 185 | call by name, means we call the left first 186 | call by value, means we call the right first 187 | 188 | (Lx.Ly.y)(x (La.a a) ((Lc.c) d)) 189 | call by name is always going to be left first (not do not eval argument until you have to) 190 | call by value is right first (argument first) 191 | 192 | perform one beta reduction using call by name 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /lecture_code/may4/lec2.txt: -------------------------------------------------------------------------------- 1 | teach to the quiz :( 2 | 3 | onwership 4 | let x = 5; // 5 | let y = x; //y has the value of 5 6 | let z = x + y; 7 | 8 | who is the owner of the value 5? 9 | y is a variable that is the owner of a value 5 10 | 11 | both x and y are variables that are the owners of values 5 12 | 13 | def: a value has a variable that is its owner 14 | 15 | flat types/scalar types (primitives) are copied and stored on the stack 16 | intgers 17 | unsinged values 18 | floats 19 | bools 20 | characters 21 | 22 | this is the case: 23 | |x:5 | 24 | |y:5 | 25 | |z:10| 26 | 27 | it is not the case: 28 | |x:5 | 29 | |y:x^| 30 | |z:10| 31 | 32 | 33 | borrowing 34 | let x = String::from("hello"); //x is the owner of hello and is a immutable reference to hello 35 | let y = &x; //y is a immutable reference here and it is not the owner of hello 36 | 37 | reference is simlar to a C pointer 38 | so x is a reference to the hello value, and is also the owner 39 | 40 | let mut x = String::from("hello") 41 | let z = &mut x; 42 | 43 | we are allowed, only 1 mutable reference at a time in rust 44 | after line 41 is executed, z is the mutable reference, and x is invalid until z goes out of scope 45 | 46 | let mut x = String::from("hello") 47 | let z = &x; // z is a immutable reference to hello, and x is also immutable 48 | x.push_str("World") <- fails 49 | because z is immutable and cannot treat x as mutable while there are immutable references 50 | ... 51 | println("{}",z) 52 | 53 | let mut x = String::from("hello") 54 | {let z = &mut x; //z is the mutable reference 55 | z.push_str("world") //we can do this 56 | println("{}",x); <- fails since z is a mutable reference and we cannot use x as a reference 57 | println("{}",z); 58 | } 59 | println("{}",x); 60 | 61 | how many (im)mutable references to value _____ at line ____ 62 | write code/fill in the blank, etc, -> where you need to borrow a a value 63 | does this code compile? 64 | 65 | 66 | lifetimes 67 | {let z = &mut x; 68 | z.push_str("world") 69 | println("{}",z); 70 | println("{}",x); 71 | } 72 | println("{}",x); 73 | 74 | 75 | what is the lifetime of x? 76 | which has a shorter/longer lifetime? x or z? 77 | when does lifetime of z end? 78 | when does lifetime of x start? 79 | 80 | lifetimes in rust are complicated 81 | the reason we have lifetimes is to avoid dangling pointers 82 | 83 | that is, we want to make sure that any reference points to a valid segment of mem 84 | 85 | a lifetime is an extension of type in rust 86 | x+1 -> x:int 87 | y+3.14 -> y:float 88 | 89 | x:u32 with a lifetime of 'a 90 | y:f64 with a lifetime of 'b 91 | 92 | a:u32 is not the same as b:&'a u32 (u32 with a lifetime of 'a) 93 | similarly to how 94 | int a is different to int* b; 95 | 96 | very much like ocaml does type inference 97 | let f x = x + 1 and ocaml infers x to be an int 98 | 99 | rust does "lifetime inference" 100 | fn longest(a:&str, b:&str) -> &str 101 | rust will try to infer a lifetime for these variables 102 | fn longest(a:&'a str, b:&'a str) -> &'a str 103 | 104 | 105 | 1)compiler will assigned different lifetime parameters to each input 106 | fn foo(x:&'a u32) 107 | fn bar(x:&u32, b:&f32) 108 | then rust will infer 109 | fn bar(x:&'a u32, b:&'b f32) 110 | 2) if one lifetime parameter, then output has the same lifetime param 111 | fn foo(x:&u32) -> &u32 112 | rust will infer 113 | fn foo(x:&'a u32) -> &'a u32 114 | 3) if multiple lifetime paramaters, AND one of params is self or &self, then output is same as (&)self 115 | fn bar(self,x:&u32, b:&f32) -> &bool 116 | rust will infer 117 | fn bar('a self,x:&'b u32, b:&'c f32) -> &'a bool 118 | 119 | what happens when we have the following? 120 | fn bar(x:&u32, b:&f32) -> &bool 121 | rust will infer the following 122 | fn bar(x:&'a u32, b:&'b f32) -> &'? bool 123 | in this case, rust cires because it donesn't know what to do. 124 | we need to help out the rust compiler by making all lifetimes explict 125 | fn bar(x:&'a u32, b:&'b f32) -> &'a bool 126 | 127 | important to note: writing the explicit lifetimes only helps the rust compiler know what to look for. 128 | It does not actually change the lifetimes of anything 129 | 130 | fn longest(a:&'a u32, b:&'a u32) -> &'a u32{ 131 | if a>b {a} else {b} 132 | }// this means that a and b live AT LEAST as long as the return value 133 | which means, a and b could have different lifetimes 134 | a lives longer than return 135 | b lives longer than return 136 | a and ret have the same lifetime 137 | b and ret have the same lifetime 138 | 139 | the only thing that will not allow this to compile, is if either a or b live shorter than ret 140 | ^ above will compile 141 | 142 | we are dependent on the return value's type (lifetime) 143 | 144 | when we talk about lifetimes in rust then we can say that lifetimes are always relative to each other 145 | 146 | fn longest(a:&'a u32, b:&'b u32) -> &'a u32{ 147 | if a>b {a} else {b}//expecting a u32 type with a lifetime of 'a, but got instead a u32 type with a lifetime of 'b 148 | } 149 | this will not compile 150 | 151 | fn longest(a:&'a u32, b:&'b u32) -> String{ 152 | if a>b {a} else {a} 153 | "hello" 154 | } 155 | this will compile 156 | 157 | 1 let x = 4; //x is created here so life begins 158 | 2 let y = 3; //y is created, so it born 159 | 3 let z = x + y; //z is created, so into the world it comes 160 | 4 println!("{}", z);//z is last used to be forgotten forever in a shallow grave 161 | 5 println!("{}", y); //y is last used so it it life comes to end after this line 162 | 6 println!("{}", x); //x is last used so the is the final breaths of x, it will soon die on line 7 163 | 164 | lifetimes: variable and values 165 | 166 | 167 | 168 | 169 | rust, what is differnt from namespacing and methods 170 | String::from "hello".len 171 | 172 | struct Rec{ 173 | width:u32, 174 | height:u32, 175 | } 176 | 177 | methods and functions are not really the same. methods are functions associated with an object 178 | 179 | impl Rec{ 180 | fn area(&self) -> u64{ 181 | self.width * self.height 182 | } 183 | } 184 | 185 | let r1 = Rec{width:5,height:10}; 186 | println!("{}",r1.area()) 187 | 188 | impl Rec{ 189 | pub fn numSides(){ 190 | 4 191 | } 192 | } 193 | println!("A rec has {} number of sides", Rec::numSides); 194 | 195 | 196 | fn foo(x:u32) -> f64{ 197 | x as f64 198 | } 199 | 200 | 201 | String::from("hello") 202 | 203 | 204 | Random r = new Random() 205 | r.new_Int(); 206 | 207 | Random.new_int(); 208 | 209 | fn main(){ 210 | let x = String::from("hello"); 211 | let res; 212 | { 213 | let y = String::from("bye"); 214 | res = shortest(&x,&y); 215 | let z = &x; 216 | } 217 | println!("{}",res); 218 | }this does not compile 219 | 220 | fn shortest(a:&'a u32, b:&'a u32) -> &'a u32{ 221 | if a > b {a} else {b} 222 | } 223 | -------------------------------------------------------------------------------- /lecture_code/may4/lec3.txt: -------------------------------------------------------------------------------- 1 | rust stuff 2 | rust quiz review 3 | final exam review pt1 4 | 5 | topics we will not test you on but are fun and interesting 6 | property based testing 7 | esoteric languages :( 8 | 9 | rust quiz review 10 | ownership -> practice question 11 | 12 | who is the owner of ____ at line _____ 13 | let x = 5; 14 | let y = x; 15 | let z = x + y; 16 | println!("{},{},{},x,y,z); 17 | |x:5 | 18 | |y:5 | 19 | |z:10| 20 | 21 | integers 22 | unisigned values 23 | bools 24 | floats 25 | characters 26 | "string" 27 | 28 | let s = String::from("hello"); 29 | let res = fn foo(s); 30 | 31 | fn foo(x:String) -> String{ 32 | x 33 | } 34 | 35 | let s = String::from("hello"); 36 | let res = fn foo(&s); 37 | //at this momement in time, res and s point to "hello", s is owner 38 | 39 | fn foo(x:&String) -> String{ 40 | *x 41 | } 42 | 43 | borrowing 44 | how many (im)mutable referenes to ___ are there at line _____ 45 | does this compile? 46 | 47 | borrowing occurs and onwership is not transfered or moved 48 | let x = Sting::from("hello"); 49 | let y = &x; //y is the borrower of the value hello from x. x is owner 50 | 51 | let mut x = Sting::from("hello"); 52 | { let y = &x; 53 | println!("{}",y); 54 | } 55 | x.push_str("world"); 56 | println!("{}",x); 57 | 58 | let mut x = ... 59 | let z = &mut x; 60 | 61 | let x = .... 62 | let z = &mut x; 63 | 64 | let mut x = Sting::from("hello"); //x is the owner and has mut ref 65 | { let y = &mut x; //y has the mut reference to hello and x is invliad 66 | // until y's lifetime ends 67 | let z = &mut x <- this would fail 68 | println!("{}",y); 69 | }//y is dropped so x is now a valid mutable reference 70 | 71 | let x = String::from("hello"); 72 | let y = &x; 73 | let z = &y; 74 | println!("{}",z); 75 | 76 | general: will this code compile or does it violate rules of ownership/references/lifetimes 77 | 78 | lifetimes 79 | what is the lifetime of ____? 80 | which has a longer/shorter lifetime? __ or __ 81 | which variable's scope is the same as it's lifetime 82 | 83 | explict lifetimes 84 | 85 | so in rust, a lifetime is an extension of type 86 | x + 1 -> x:int 87 | x +. 4.0 -> x:float 88 | 89 | String x = ne String() 90 | Integer y = new Integer() 91 | 92 | x:u32 93 | y:&'a u32 -> y is a u32 referenece with a lifetime of 'a 94 | z:&'b u32 -> z is a u32 referenece with a lifetime of 'b 95 | 96 | how does rust deal with lifetimes? 97 | 98 | ocaml does type inference 99 | let f x = x + 1 and ocaml will infer that x is an int 100 | 101 | rust does "lifetime" inference 102 | fn longest(x:&u32) -> &u32 103 | rust will infer lifetimes for these parameters and return value. 104 | 105 | 1) the compiler will give you a different lifetime for all input references 106 | fn longest(x:&u32) -> &u32 107 | rust will infer 108 | fn longest(x:&'a u32) -> &u32 109 | fn longest(x:&u32,y:&u32) -> &u32 110 | rust will infer 111 | fn longest(x:&'a u32,y:&'b u32) -> &u32 112 | 2) if there is one lifetime param, then output get that same param 113 | fn longest(x:&u32) -> &u32 114 | rust will infer 115 | fn longest(x:&'a u32) -> &'a u32 116 | 3) if there is multiple lifetime params, AND one of the params is self or &self, then the output lifetime is the same as self/&self. 117 | 118 | fn longest(&self, x:&u32,y:&u32) -> &u32 119 | rust will infer 120 | fn longest(&'a self, x:&'b u32,y:&'c u32) -> &'a u32 121 | 122 | fn longest(x:&u32,y:&u32) -> &u32 123 | how will rust inter? 124 | fn longest(x:&'a u32,y:&'b u32) -> &'? u32 125 | so in this case, rust cries because it doesn't know what to do 126 | rust compiler needs help 127 | in order to help the compiler, we need to make all lifetimes explict 128 | fn longest(x:&'a u32,y:&'a u32) -> &'a u32 129 | 130 | important: this just helps the compiler know what to do. 131 | Explicit lifetime annotations does not actually change the lifetime of anything. 132 | 133 | fn longest(x:&'a u32,y:&'a u32) -> &'a u32 134 | lifetimes prevent things like dangling pointers 135 | 136 | dependent on return lifetime 137 | the parameters are bound to the return lifetime 138 | 139 | fn longest(x:&'a u32,y:&'a u32) -> &'a u32 //return type is &'a u32 140 | lifetimes are relative, we just need to make sure that whatever we are referencing is living at least as long as the reference. 141 | 142 | the parameters with the same lifetime as the return must live at least as long as the return value. 143 | 144 | fn longest(x:&'a u32,y:&'a u32) -> &'a u32 145 | x, y, and ret all have the same lifetime 146 | x>=y>=ret 147 | y>=x>=ret 148 | both are fine 149 | 150 | 151 | fn longest(x:&'a u32,y:&'a u32) -> &'a u32{ 152 | if x > y {x} else {y} 153 | }this would compile 154 | 155 | fn longest(x:&'a u32,y:&'b u32) -> &'a u32{ 156 | if x > y {x} else {y} 157 | }this would not compile because of mismatched return type 158 | 159 | fn longest(x:&'a u32,y:&'b u32) -> &'a u32{ 160 | if x > y {x} else {x} 161 | }this does compile 162 | 163 | fn longest(x:u32,y:u32) -> u32{ 164 | if x > y {x} else {y} 165 | }this does compile 166 | 167 | fn longest(x:&'a u32,y:&'b u32) -> &'a u32 168 | 169 | fn longest(x:&'a u32,y:&'b u32) -> &'b u32 170 | fn longest(x:&'a str,y:&'b str) -> &'b str 171 | 172 | let s = String::from("hello") 173 | 174 | -------------------------------------------------------------------------------- /lecture_code/ocaml/expr.ml: -------------------------------------------------------------------------------- 1 | int things 2 | +, -, *, / 3 | (e1:int + e2:int):int 4 | 5 | float things 6 | +., -., *., /. 7 | (e1:float +. e2:float ):float 8 | 9 | string things 10 | (e1:string ^ e2:string):string 11 | 12 | bool things 13 | &&, ||, ! 14 | (e1:bool && e2:bool):bool 15 | 16 | conditionals 17 | (if (e1:bool) then e2:'a else e2:'a):'a 18 | 19 | let expressions 20 | (let x = e1:'a in x):'a 21 | (let x a1:'a a2:'b ...= e1:'tx in x):'a->'b->...->'ty 22 | (let x = e1:'a in e2:'b):'b 23 | 24 | function calls 25 | (f x1 x2 ...) 26 | which has type: 27 | (f: 'a 'b ... -> 't x1:'a x2:'b ...):'t 28 | 29 | list things 30 | ([e1:'a;e2:'a;...]):'a list 31 | (e1:'a :: e2:'a list):'a list 32 | 33 | tuples 34 | ((e1:'a,e2:'b,...)):'a * 'b *... 35 | 36 | pattern match 37 | (match e1:'a with 38 | p1 -> e1:'b 39 | |p2 -> e2:'b 40 | ... 41 | ):'b 42 | 43 | constants 44 | 1:int 45 | 1.3:float 46 | true:bool 47 | "String":string 48 | (fun x -> x + x):int -> int 49 | 50 | variants (not expression. Is a definition) 51 | (type x = A|B|...):x 52 | (type x = {var1:'a;var2:'b;...}:x 53 | 54 | let bindings (not expressions, different than let expressions) 55 | (let x = expr1:'t):'t;; 56 | (let f x:'a y:'b ... = expr1:'t) 'a -> 'b -> ... 't);; 57 | 58 | let x = 5;; 59 | x + 6;; 60 | 61 | 5 + 6 62 | 63 | (fun a1 a2 a3... -> e) 64 | 65 | let area l w = l*w;; 66 | 67 | 68 | let area l w = l * w 69 | 70 | let area = (fun l w -> l * w);; 71 | 72 | let area = fun l -> (fun w -> l * w) 73 | 74 | def genadd(x) 75 | Proc.new{|y| y + x} 76 | end 77 | 78 | add3 = gendadd(3) 79 | add4 = gendadd(4) 80 | 81 | add3.call(4) 82 | add4.call(4) 83 | 84 | let area = fun l -> (fun w -> l * w) 85 | 86 | def area 87 | Proc.new{|l| Proc.new{|w| -> l * w}} 88 | end 89 | 90 | area.call(3).call(4) 91 | 92 | def appplied(p,x) 93 | p.call(x) 94 | end 95 | 96 | 97 | let applied f x = f x;; 98 | 99 | 100 | let rec map f l = match l with 101 | [] -> [] 102 | |h::t -> (f h)::(map f t);; 103 | 104 | ('a -> 'b) -> 'a list -> 'b list 105 | 106 | let add3 x = x + 3 107 | 108 | map add3 [1;2;3] 109 | match [1;2;3] with 110 | [] -> [] 111 | h::t -> 4::5::6::[];; 112 | [4;5;6] 113 | 114 | map add3 [] 115 | match [] with 116 | [] -> [] 117 | |h::t -> add3 h .... 118 | 119 | map add3 [3] 120 | match [3] with 121 | []-> [] 122 | |h::t -> 6::(map add3 []) 123 | h:3 124 | t:[] 125 | 126 | map add3 [2;3] 127 | match [2;3] with 128 | [] -> [] 129 | |h::t -> (5::map add3 [3]) 130 | 131 | l: [2;3] 132 | f:add3 133 | h:2 134 | t:[3] 135 | -------------------------------------------------------------------------------- /lecture_code/ocaml/expresions.txt: -------------------------------------------------------------------------------- 1 | (expr1:int + expr2:int):int 2 | 5:int 3 | 6:int 4 | (5:int + 6:int):int 5 | 6 | ((5:int + 6:int):int + 7:int):int 7 | (5:int + (6:int:int + 7:int)):int 8 | 9 | (expr1:int + expr2:int):int 10 | (expr1:int - expr2:int):int 11 | (expr1:int * expr2:int):int 12 | (expr1:int / expr2:int):int 13 | 14 | true:bool 15 | (true || false):bool 16 | false:bool 17 | 18 | (if expr1:bool then expr2:t else expr3:t):t 19 | 20 | if true then false else true;; 21 | (if true:bool then false:bool else true:bool):bool;; 22 | expr1: true:bool 23 | expr2: false:bool 24 | expr3: true:bool 25 | 26 | if true then 3 else 4;; 27 | (if true:bool then 3:int else 4:int):int;; 28 | expr1: true:bool 29 | expr2: 3:int 30 | expr3: 4:int 31 | 32 | (if (true||false) then 3+4 else 5;; 33 | expr1: (true||false):bool 34 | expr2: 3+4:int 35 | expr3: 5:int 36 | 37 | if false then 5 else 6;; 38 | expr1: (if true then false else true): bool 39 | -> e1 -> true:bool 40 | -> e2 -> false:bool 41 | -> e3 -> true:bool 42 | => false:bool 43 | expr2: 5:int 44 | expr3: 6:int 45 | 46 | These are the same 47 | --------------- 48 | def x 49 | 3 50 | end 51 | 52 | x + 3 53 | -------------- 54 | y = 3 55 | y + 3 56 | -------------- 57 | 58 | (let name arg1:t1 arg2:t2...argx:tx = expr:t):t1->t->..->tx->t 59 | (let name = expr:t):t 60 | 61 | (let add3 x:int = x:int + 3): int->int 62 | 63 | let f a b c d = if true then a > b else c > d;; 64 | arg1: a: 'a 65 | arg2: b: 'a 66 | arg3: c: 'b 67 | arg4: d: 'b 68 | return: bool 69 | 'a -> 'a -> 'b -> 'b -> bool 70 | 71 | -------------------------------------------------------------------------------- /lecture_code/ocaml/hof.ml: -------------------------------------------------------------------------------- 1 | let rec map f l = match l with 2 | [] -> [] 3 | |h::t -> (f h)::(map f t);; 4 | 5 | ('a -> 'b) -> 'a list -> 'b list 6 | 7 | 8 | let add3 x = x + 3 in 9 | map add3 [1;2;3] 10 | 4::5::6::[] 11 | 12 | map add3 [1;2;3] 13 | (int -> int) -> int list -> int list 14 | 15 | map (fun a,b -> a + b) [(1,2);(3,4)] 16 | (int*int -> int) -> int *int list -> int list 17 | 18 | map (fun f -> f 3) [(fun x -> x + 1);(fun x -> x -2)]; 19 | ((int->int) -> int) -> (int -> int) list -> int list 20 | 21 | let rec foldl f a l = match l with 22 | [] -> a 23 | |h::t -> foldl f (f a h) t;; 24 | 25 | ('a -> 'b -> 'a)-> 'a -> 'b list -> 'a 26 | 27 | the function is going take some value and update it with 28 | each item in the list 29 | evaluates list left -> right 30 | 31 | fold takes in a total value, a function, and a list 32 | and updates the total with the function and each item in the list 33 | and returns the total value 34 | 35 | a::b vs a@b;; 36 | a:'a :: b:'a list 37 | a:'a list @ b:'a list 38 | 39 | 40 | let rec foldl f a l = match l with 41 | [] -> a 42 | |h::t -> foldl f (f a h) t;; 43 | 44 | let sum a b = a + b in 45 | foldl sum 0 [1;2;3] 46 | 47 | match [1;2;3] with 48 | [] -> 0 49 | |h::t -> foldl sum 1 [2;3];; 50 | 51 | foldl sum 1 [2;3] 52 | match [2;3] with 53 | [] -> 1 54 | |h::t -> foldl sum 3 [3] 55 | 56 | foldl sum 3 [3] 57 | match [3] with 58 | [] -> 3 59 | |h::t -> fold sum 6 [] 60 | 61 | fold sum 6 [] 62 | match [] with 63 | [] -> 6 64 | 65 | let rec foldr f l a -= match l with 66 | [] -> a 67 | |h::t -> f h (foldr f t a) 68 | 69 | foldr -> 3 + 2 + 1 -> 6 70 | 1 + 2 + 3 = 3 + 2 + 1 71 | 1 - 2 -3 != 3 - 2 - 1 72 | 73 | foldl (fun (a,b) x -> (a+h,b+1)) (0,0) [1;2;3] 74 | 75 | join 76 | ["a","b","c"].join -> "abc" 77 | 78 | let joinf lst = foldl (fun a h -> a ^ h) "" lst 79 | 80 | let rec join lst = match lst with 81 | [] -> "" 82 | |h::t -> h ^ (join t);; 83 | 84 | let rec join lst = 85 | let rec join2 lst a = match lst with 86 | [] -> a 87 | |h::t -> join2 t (h^a) in join2 lst;; 88 | 89 | countif takes in a predicate and alist and counts how many items in the list make the predicate true 90 | 91 | let countif pred lst = 92 | foldl 93 | (fun a x -> if pred x then a+ 1 else a) 94 | 0 95 | lst 96 | 97 | powerset of list return a list of all possible subsets 98 | 99 | [1;2;3] 100 | [[];[1];[2];[3];[1;2];[1;3];[2;3];[1;2;3]] 101 | 102 | 'a list -> 'a list list 103 | 104 | let powerset lst = fold f [] lst 105 | 106 | f: -> 'a -> 'a list list 107 | 108 | let build acc ele = match acc with 109 | [] -> [[ele]] 110 | |h::t -> let res = map (fun x -> ele::x) acc 111 | in [ele]::(res @ acc);; 112 | 113 | let powerset lst = []::lst::(fold build [] lst);; 114 | 115 | powerset [1;2;3];; 116 | 117 | build 1 [[2];[3]] -> [[1];[2];[3];[1;2];[1;3]] 118 | res = map ... -> [[1;2];[1;3]] 119 | temp = [1]::res -> [[1];[1;2];[2;3]] 120 | temp @ [[2];[3]] -> [[1];[1;2];[2;3] [2];[3]] 121 | 122 | fold is a the higher level idea of taking a value and a list and updating the total based off the items in the list 123 | 124 | map takes in a list and a function. For each item in the list, call the function on it and get a result r back. Then add r to a list of other results 125 | 126 | map (fun x -> x + 3) [1;2;3] 127 | -> [4;5;6] 128 | -------------------------------------------------------------------------------- /lecture_code/ocaml/hw.ml: -------------------------------------------------------------------------------- 1 | print_string "Hello World!\n" 2 | -------------------------------------------------------------------------------- /lecture_code/ocaml/lets_lists_patterns.ml: -------------------------------------------------------------------------------- 1 | (let var = e1:t1 in e2:t2):t2 2 | 3 | let x = 3 in x + 4;; 4 | var: x 5 | e1: 3 6 | t1:int 7 | e2:x+4 8 | t2:int 9 | 10 | 1. e1 is evaluated to a value, v1 11 | 2. bind v1 to the varaible var, v1:var 12 | 3. evaluate e2 knowing {v1:var} to a value v2 13 | 4. return v2 14 | 15 | let x = 3 in 4 16 | 3=>3 17 | 3:x 18 | 4 knowing 3:x => 4 19 | 4 20 | 21 | 22 | (let var = e1:t1 in e2:t2):t2 23 | 24 | 1. e1 is evaluated to a value, v1 25 | 2. bind v1 to the varaible var, v1:var 26 | 3. evaluate e2 knowing {v1:var} to a value v2 27 | 4. return v2 28 | 29 | let x = 3 in let x = 4 in x + x 30 | let x = 3 in z 31 | let x = 3 in 8 32 | z = let x = 4 in x + x => 8 33 | 34 | 35 | e1:3=>3 36 | t1:int {x:3} 37 | e2: let x = 4 in x + x 38 | t2:int 39 | 40 | subexpr-e2 {3:x} 41 | let x = 4 in x + x 42 | e1: 4+.4 43 | t1: int {4:x} 44 | e2: x + x => 4 + 4 => 8 45 | t2: int 46 | :int 47 | 48 | let x = let x = 3 in x + 1 in x + 2;; 49 | e1: let x = 3 in x + 1 => 4 50 | e2: x + 2 {4:x} => 6 51 | 52 | let x = 4 in let x = x + 4 in x;; 53 | let x = 4 in let y = x + 4 in y;; 54 | 55 | def area r 56 | pi = 3.14 57 | return pi * r * r 58 | end 59 | 60 | let area r = let pi = 3.14 in pi *. r *. r;; 61 | 62 | ([e1:t;e2:t;...;ex:t]):t list 63 | 64 | (e1:t :: e2:t list):t list 65 | 66 | a.push(x) 67 | x::a 68 | 69 | 1::[2] 70 | 71 | 1::(2::[3]) 72 | 73 | list :- 74 | [] 75 | h::t 76 | h: the head or first item 77 | t: the rest of the list 78 | 79 | 80 | 81 | 0-> 1 -> 2 -> 3 -> 4 82 | 83 | lst = 1mem 84 | 85 | let lst2 = 0:: lst 86 | 87 | (match e1:t with 88 | p1 -> e2:t2 89 | |p2 -> e3:t2 90 | ... 91 | |px -> ex:t2):t2 92 | 93 | match e1 with p1 -> e2 | p2 -> e3 | px -> px;; 94 | 95 | [1] -> 1::[], h:1, t:[] 96 | [1;2;3;4] -> h:1, t:[2;3;4] 97 | 98 | (match e1:t with 99 | p1 -> e2:t2 100 | |p1 -> e3:t2 101 | ... 102 | |px -> ex:t2):t2 103 | 104 | switch(3) 105 | case(4): return 7 106 | case(5): return 6 107 | case("hello"): return 8 108 | 109 | let x = 5 in 110 | 111 | let _ = print_int 112 | (let x = [1;2;3] => 1::(2::3[]) 113 | in match x with 114 | [] -> 0 115 | |h::2::t -> h 116 | ) 117 | 118 | let length lst = match lst with 119 | [] -> 0 120 | |h::t -> 1 + length t;; 121 | 122 | 123 | let rec evens lst = match lst with 124 | [] -> [] 125 | |h::t -> if h mod 2 = 0 then h::(evens t) else evens t;; 126 | -------------------------------------------------------------------------------- /lecture_code/review/lec1.review: -------------------------------------------------------------------------------- 1 | lambda calc 2 | is turing complete (provides the "highest" level of computational ability) 3 | 4 | grammar: 5 | e -> x //a value/variable 6 | |Lx.e // a function 7 | |e e 8 | |(e) 9 | is ambiguous-> left assoc helps clarify 10 | scope of function is to end of expression or unmatched paren 11 | 12 | cbn,cbv -> precedence of ways to evaluate an expression 13 | beta reduction -> calling a function (applying a function call) 14 | alpha conversion -> changing bound vars and parameter they are bound to 15 | 16 | bound var -> variable that is depending on a function's parameter 17 | free var -> a variable that is not bound 18 | 19 | cbn (lazy) -> we are calling the function without evaluating the argument 20 | def myfunc(x) 21 | x + 1 22 | end 23 | 24 | myfunc(1+3) -> 1 + 3 + 1 25 | 26 | cbv (eager) -> evaluate the argument before the function call 27 | myfunc(1+3) -> myfunc(4) 28 | 29 | e1 -> v1 e2 -> v2 v3 is v1 + v2 30 | ------------------------------------- 31 | e1 + e2 => v3 32 | add(e1,e2) === e1 + e2 33 | the above is cbv 34 | 35 | 36 | 37 | e3 is e1 + e2 e3 => v 38 | ------------------------------------- 39 | e1 + e2 => v 40 | this is analogous to cbn 41 | 42 | Scoping 43 | Lx. a b c 44 | _ _____ 45 | 46 | def func(x) 47 | a 48 | b 49 | c 50 | end 51 | 52 | (Lx. a b) c 53 | def func(x) 54 | a 55 | b 56 | end 57 | c 58 | 59 | 60 | (Lx. x x) x --alpha convert -> (Ly. y y) x 61 | p b b f 62 | def func(x) <- parameter def func(y) 63 | x <- bound y 64 | x <- bound y 65 | end end 66 | x <- free x 67 | 68 | 69 | (Lx.(Lx. x x) x) --alpha convert -> (Lx. (Ly. y y) x) -beta reduc -> (Lx. x x) 70 | - - - 71 | _ _ 72 | fun x -> (fun x -> x;x) 73 | def func(x) 74 | - 75 | Proc.new{|x| x x} 76 | _ _ _ 77 | x 78 | - 79 | end 80 | 81 | beta normal form: you cannot call a function at all 82 | 83 | fn longest(a:&'a str, b:&'a str) -> &'a str{ 84 | 85 | } 86 | 87 | ((b c) (λb. a)) ((λa. c) (λa. b)) 88 | e1 e2 89 | let's call this expression inference 90 | e -> e 91 | | Lx. e 92 | | e1 e2 93 | 94 | (a b) c 95 | --- - 96 | e1 e2 97 | rule of lambda calc -> left assoc 98 | 99 | 100 | Lx. a b c <- must be correct due to scoping rules 101 | - ----- 102 | x e 103 | 104 | Lx. a b c 105 | - - --- 106 | x e 107 | e1 e2 108 | 109 | 110 | 111 | 112 | CFG 113 | describe a set of string 114 | can be recursive (describes a recursively defined set) 115 | S -> aS | a 116 | S = {a, 117 | x \in S => ax 118 | describes grammatically correct "sentences" which helps the parser phase 119 | they decribe more than regular languages 120 | (can compute more than a regular language) 121 | CFGs can be ambiguous -> but any ambiguous CFG can be converted to non ambiguous 122 | a set is ambiguous if we can derive a value in a set using 123 | > 1 left most derivation OR 124 | > 1 right most derivation 125 | if 1 right and 1 left most derivation exist, not nec. ambiguous 126 | 127 | left most derivation 128 | when given a defintion with multiple recursive calls, we call the left one first 129 | S -> S + S|1 130 | derive 1 + 1 + 1 131 | S -> S + S -> 1 + S S -> S + S -> S + S + S -> 1 + S + S 132 | _ _ _ _ _ _ _ _ _ 133 | L R L R L NL R L R 134 | not concrete but some good hueristics of id'ing a ambiguopus grammar 135 | + if there is a symmetric def -> S + S 136 | + if a recursive call can be done at any level -> S -> aS|Sa|a 137 | S -> aS -> aSa -> aaa 138 | S -> Sa -> aSa -> aaa 139 | 140 | 141 | HOF 142 | a higher order function (HOF) is a function that 143 | returns a fcuntion OR 144 | takes in another function as a parameter 145 | 146 | Map and Fold are examples (we talked about them because they are common) 147 | the reason they are common, is because they represent very common for loops 148 | map is a more specific version of fold 149 | 150 | so ultimately fold is a way to get looping recursively (fold is a for loop) 151 | 152 | fun x -> fun y -> x + y is not a loop, but also is HOF 153 | fun x -> (fun y -> y + 1) takes in a value and returns a function 154 | 155 | fun x a -> (x a) + 1 takes in a function as a parameter and returns an int 156 | 157 | fun x a -> x a takes in a function and possibly returns a function 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /lecture_code/review/lec2.review: -------------------------------------------------------------------------------- 1 | lambda calc 2 | cfgs and regex 3 | currying 4 | ocaml and ruby 5 | 6 | lambda calc 7 | is turing complete(language has the "highest" amount of computational ability) 8 | cbn and cbv (found in other languages) 9 | left assoc (a rule that helps make an expression non-ambiguous) 10 | e -> x (variables) 11 | |Lx.e (functions) 12 | |e e (compounds) 13 | (this grammar is ambiguous) 14 | 15 | beta reduction -> a function call (or apply a function) 16 | alpha conversion -> renaming bound vars and their parameter 17 | 18 | bound var -> a variable that is dependent on a function's parameter 19 | free var -> a variable that is not bound (nor a param) 20 | 21 | beta normal form -> we cannot call anymore functions 22 | 23 | cbn and cbv are just precedence rules of how to call a fuction 24 | 25 | cbn (lazy): calling a function without evalutating the argument 26 | def myfunc(x){ 27 | x + 1 28 | } 29 | 30 | myfunc(1+3) -> 1 + 3 + 1 31 | (Lx. ___) (e) 32 | ((Lx. ____) (Ly. ____)) d 33 | (let x = (fun y -> ...) in body of x) d 34 | 35 | cbv (eager): evaluating the argument before the function call 36 | 37 | myfunc(1+3) -> myfunc(4) -> 4 + 1 38 | 39 | aside: opsem 40 | 41 | e1 -> v1 e2 -> v2 v3 is v1 + v2 42 | ------------------------------------- 43 | e1 + e2 => v3 44 | v1,toks = eval e1 45 | v2,toks = eval e2 46 | return v1 + v2 47 | 48 | add(e1,e2) === e1 + e2 49 | the above rule is call by value 50 | 51 | e3 is e1 + e2 e3 -> v 52 | ------------------------------------- 53 | e1 + e2 => v 54 | the above rule is call by name 55 | 56 | (Lx. (Ly. y y) x) -> beta reduction (Lx. x x) 57 | cbn, cbv are just precedence rules 58 | 59 | explicit parens 60 | 61 | e -> x 62 | |Lx. e 63 | | e e 64 | |(e) 65 | 66 | a b c 67 | --- - 68 | e1 e2 69 | 70 | a b c 71 | - --- 72 | e1 e2 73 | 74 | rules of lambda calc 75 | + left assoc 76 | + scope of function is until end of expression or unmatched paren 77 | 78 | fn longest(a:&str, b:&str) -> &str <- does not compile in rust due to lack of lifetime inference 79 | 80 | given an expression in lambda calc, we are going to do expression inference 81 | 82 | 83 | a b c <- due to left assoc rules, this is correct 84 | --- - 85 | e1 e2 86 | 87 | a b c <- due to left associ rules, this is incorrect 88 | - --- 89 | e1 e2 90 | 91 | Lx. a b c <- due to scoping rules, this is correct 92 | _ _____ 93 | x e 94 | 95 | Lx. a b c <- due to scoping rules, this is incorrect 96 | _ _ ___ 97 | x e 98 | e1 e2 99 | 100 | explict parens don't change expression, just helps use parse/evalu the expresion 101 | 102 | a b (Lx. x) ((Lx. a) (Lc. b)) 103 | e e e e e 104 | e1 e2 e3 e4 105 | (e1 e2) e3 e4 106 | ((e1 e2) e3) e4 107 | (((e1 e2) e3) e4) 108 | a b ((Lx. x) ((Lx. a) (Lc. b))) is not the same as above 109 | 110 | -> beta reduc 111 | -> 112 | (((a b) (Lx. x)) ((Lx. a) (Lc. b))) 113 | (((a b) (Lx. x)) (a)): this is in beta normal form 114 | 115 | a b (lx.x) a -> this is also beta normal form 116 | (Ly. x y) (Lx.x) a 117 | e e e 118 | (e e) e 119 | ((Ly. x y) (Lx.x)) a 120 | (x (lx.x)) a 121 | 122 | e1 e2 123 | and e1 is a function, we can beta reduce 124 | if e1 is not a function, we cannot reduce e1 e2 except if e2 can be reduced 125 | 126 | if neither cbv and cbv have infinite loops, they have the same BNF 127 | if one is not terminiating, then they do not evalute the same way 128 | 129 | 130 | CFGs and regex 131 | 132 | CFGs 133 | a CFG describes a set of srings 134 | to describe a set, its going to use a recursivly defined set notation 135 | S -> aS|a 136 | S = { a, 137 | x \in S => ax 138 | 139 | we can do more with cfgs than regex 140 | (computation ability > regular language) 141 | fsm and regex (regular languages) are computationally the same 142 | cfgs can compute everything a regular language can computer plus some 143 | non terminals, production, terminals 144 | describe the grammar of a language 145 | useful to determine if a "sentence" is grammatically correct (parsing phase) 146 | grammars can be ambiguous 147 | left most derivation vs a right most derivation 148 | when expanding the grammar, we expand the left most recursive call first 149 | 1 + 1 + 1 150 | S -> S + S | 1 151 | S -> S + S -> 1 + S -> 1 + S + S -> 1 + 1 + S -> 1 + 1 + 1 152 | L R 153 | S -> S + S -> S + S + S -> 1 + S + S -> 1 + 1 + S -> 1 + 1 + 1 154 | when given mutliple rec calls, evaluate the left most first 155 | if a string has (note, \exists not \forall) 156 | > 1 left most derivation OR 157 | > 1 right most derivation 158 | then it is ambiguous 159 | if 1 left and 1 right, it is not nec. ambiguous 160 | 161 | S -> 1 + S | 1 162 | 163 | not concrete, but good hueristics for id'ing ambiguous grammars 164 | + if there is a symmetric recursive definiton: S + S 165 | + if you can use the recusive calls at different "levels" 166 | S -> aS | Sa | a 167 | S -> aS -> aSa -> aaa 168 | S -> Sa -> aSa -> aaa 169 | rephrase: you can use different recursive calls at the same step 170 | 171 | S -> S + S | T 172 | T -> T - T | 1 173 | 174 | not concrete but good hueristics for relative numbering of grammars 175 | a^xb^y x>= 3y, x>=y>=1 176 | 177 | for every b, I need at least 3 'a's 178 | aaab 179 | if zero bs, then at least 0 a 180 | we can obtain a >= (at least) relation 181 | a+ aa* -> at least 3 as is the same as aaaa* 182 | S -> aaaTSb|aaaTb // maintains the aaaa* for every b relation 183 | T -> aT|e //a* 184 | rephrase: chain together known cfgs relations (common known cfgs are a* or variations) 185 | 186 | parse tree vs ast: both ways to model a grammatically correct sentence 187 | S -> S + S | 1 188 | 1 + 1 + 1 189 | parse tree cares about the symbols that we saw 190 | S 191 | / |\ 192 | / || 193 | S | \ 194 | /|\ | | 195 | S + S | S 196 | | | | | | 197 | 1 + 1 + 1 198 | 199 | an ast cares about the operations we want to consider 200 | + 201 | / \ 202 | + \ 203 | / \ | 204 | 1 + 1 + 1 205 | 206 | the ast is better input for an evaluator than a parse tree 207 | 208 | ruby: 209 | imperative 210 | built in regex 211 | everything is an object 212 | support procs and code blocks 213 | uses a garbage collector 214 | latent typing 215 | 216 | static and dynamic when is type checking done (compiler or run time) 217 | latent and manifest (type is associated with value, not variable) 218 | (what is a type associated with) 219 | -------------------------------------------------------------------------------- /lecture_code/review/lec3.review: -------------------------------------------------------------------------------- 1 | lambda calc 2 | cfgs 3 | hof 4 | rust stuff 5 | 6 | lambda calc 7 | is turing complete (has the "highest" amount of computational ability) 8 | is a minimal turing complete language 9 | 10 | there are functions in this language 11 | left assoc 12 | we can beta reduce expression (sometimes multiple ways) 13 | lazy or eager (cbn/cbv) are ways of evaluating (found in other languages) 14 | 15 | e -> Lx.e (function) 16 | |x (variable) 17 | |e e (compound) 18 | this grammar is ambiguous 19 | we can add parenthesis to remove ambiguity 20 | e -> (e) 21 | free vs bound vars 22 | bound can be alpha converted 23 | 24 | scoping rules for functions (scope goes to end or paren) 25 | 26 | bound var: a variable that is dependent on the parameter of a lambda function 27 | free var: a variable that is not bound (nor a param) 28 | 29 | alpha conversion: changing the names of bound variables and their param 30 | (do this to for easy readability) 31 | 32 | (Lx. (Lx. x x x) x) x 33 | - + + + + - _ 34 | (La. (Lx. x x x) a) x 35 | (La. (Lz. z z z) a) x 36 | 37 | (Lx.x) (Lx.x) 38 | (Lx.x) (Ly.y) 39 | (Ly.y) (Lx.x) 40 | (Ly.y) (Lz.z) 41 | 42 | beta reduction: a single function call (or applying a function) 43 | beta normal form: when an expression that cannot be beta reduced anymore 44 | 45 | cbn (lazy): we do not evaluate the arguments before calling a function 46 | def func(x) 47 | x + 1 48 | end 49 | 50 | func(3+1) -> 3 + 1 + 1 51 | 52 | cbv (eager): evaluate the arguments before calling a function 53 | func(3+1) -> func(4) -> 4 + 1 54 | 55 | cbv and cbn are precedence rules (what are you going to prioritze first?) 56 | if both cbn and cbv strats terminate, then they should evaluate to the same thing 57 | if one of cbn and cbv strats do not terminate, then they evalute differently 58 | 59 | aside: opsem 60 | 61 | e1 => v1 e2 => v2 v3 is v1 + v2 62 | ------------------------------------- 63 | e1 + e2 => v3 64 | v1 toks = eval e1 65 | v2 toks = eval e2 66 | return (v1 + v2) toks 67 | 68 | this is call by value semantics 69 | add(e1,e2) === e1 + e2 70 | 71 | e3 is e1 + e2 e3 => v 72 | --------------------------- 73 | e1 + e2 => v 74 | 75 | this is call by name semantics 76 | 77 | explicit parens 78 | 79 | fn longest(a:&str, b:&str) -> &str 80 | does not compile due to rust being unable to infer lifetimes 81 | fn longer(a:u32, B:u32) -> u32 82 | this does compile 83 | 84 | in rust, there is a lifetime inference 85 | 86 | let f x = x + 1 and ocaml infers the type of x to be an int 87 | all because of rules of inference (either lifetime inference or type inference) 88 | 89 | lambda calc also has rules of inference 90 | e -> x 91 | |Lx. e 92 | |e e 93 | |(e) 94 | a b c <- due to rules of LC about left assoc, this is correct 95 | --- - 96 | e1 e2 97 | 98 | a b c <- due to rules of LC about left assoc, this is incorrect 99 | - --- 100 | e1 e2 101 | 102 | due to left assoc rules, when given e1 e2 e3 e4 .... 103 | we want to group the left 2 first 104 | (e1 e2) e3 105 | e1 e2 e3 106 | 107 | Lx. a b c <- due to scoping rules this is correct 108 | - ----- 109 | x e 110 | e 111 | 112 | Lx. a b c <- due to scoping rules, this is incorrect 113 | - - --- 114 | x e e2 115 | e1 116 | e 117 | adding explicit parens does should not change the meaning of the sentence 118 | it just helps us parse it 119 | 120 | a b (Lx.x) ((La.c) (Lx. b) b) 121 | e e e e e e 122 | ________e_________ 123 | so if we add more (explicit) parens the meaning of this expression shouldn't change 124 | 125 | (((a b) (Lx.x)) ((La.c) (Lx. b) b)) 126 | (((a b) (Lx.x)) (c b)) 127 | 128 | CFGs 129 | (can describe languages that have more computational ability that 130 | regular languages, but not all languages that are turing complete) 131 | determines if a string is grammatically correct 132 | helps us build a string 133 | a cfg describes a set of string through some rules 134 | S -> aS|a 135 | S = {a, 136 | x \in S => ax 137 | terminals, non terminals, production rules 138 | grammars can be ambiguous 139 | so grammars are useful for the parsing phase of compilation or evaluation 140 | (some such parsers include a recursive decent parser) 141 | 142 | what makes a grammar ambiguous? 143 | a grammar is ambiguous if 144 | >1 left most derivation for a string OR 145 | >1 right most derivation for a string 146 | \exists rather than a \forall 147 | if there is 1 left most derivation and 1 right most derivation, not nec ambiguous 148 | what is a left most derivation? 149 | always expand/substitute the left most recursive call 150 | S -> S + S | 1 151 | 1 + 1 + 1 152 | S -> S + S -> 1 + S -> ... 153 | L R 154 | 155 | not concrete but some good hueristics 156 | + if rec calls are symmetric S + S 157 | + if the rec calls can be done at any "level" 158 | rephrase: we can interchange rec calls 159 | S -> aS|Sa|a 160 | S -> aS -> aSa -> aaa 161 | S -> Sa -> aSa -> aaa 162 | 163 | HOF 164 | a function that takes in a function (code) as an argument 165 | a function that returns a function 166 | 167 | let f x = x 3; 168 | let f y = fun x -> x + y; 169 | 170 | we talked about 2 particular HOF (map and fold) because they are very common 171 | (they are common because they represent for loops) 172 | map is a particular case of fold 173 | (fold is just a for loop) 174 | 175 | for i in tree: 176 | do something with i 177 | 178 | let rec tree_fold f t a : needs a function, needs a tree, and needs and acc 179 | function: let f a v : needs the acculator and curr node 180 | 181 | we go through the tree by left, self, right 182 | 183 | type tree Node of int * tree * tree | Leaf 184 | 185 | let in_ord t = tree_fold (fun x -> fun y -> y::x) t [] 186 | 187 | a = Proc.new{|x| x+1} 188 | a.call(4) 189 | 190 | let a = fun x -> x + 1 191 | a 4 192 | -------------------------------------------------------------------------------- /lecture_code/ruby/cb.rb: -------------------------------------------------------------------------------- 1 | def mycb(x) 2 | puts "in mycb" 3 | if block_given? 4 | yield 5 | else 6 | puts "no block" 7 | end 8 | puts x 9 | puts "back in mycb" 10 | end 11 | 12 | 13 | def puts_hello 14 | puts "hello" 15 | end 16 | 17 | def add 18 | yield 4 19 | end 20 | 21 | def mycb 22 | a = yield 23 | puts a 24 | end 25 | 26 | mycb 27 | 28 | 29 | -------------------------------------------------------------------------------- /lecture_code/ruby/hw.rb: -------------------------------------------------------------------------------- 1 | puts "hello world" 2 | -------------------------------------------------------------------------------- /lecture_code/ruby/int.rb: -------------------------------------------------------------------------------- 1 | puts 3 + 4 2 | 3 | class Integer 4 | def +(x) 5 | "not today" 6 | end 7 | end 8 | 9 | puts 3 + 4 10 | 11 | 12 | puts 3.4 + 1.2 13 | 14 | if false then 15 | class Float 16 | def +(x) 17 | "not today" 18 | end 19 | end 20 | end 21 | 22 | puts 3.4 + 1.2 23 | 24 | if true then 25 | class Float 26 | def +(x) 27 | "not today" 28 | end 29 | end 30 | end 31 | 32 | puts 3.4 + 1.2 33 | -------------------------------------------------------------------------------- /lecture_code/ruby/methods.rb: -------------------------------------------------------------------------------- 1 | def my_s1 2 | "my String" 3 | end 4 | 5 | def my_s2 6 | s = "my String" 7 | return s 8 | end 9 | 10 | def my_s3 11 | s = "my String" 12 | s 13 | end 14 | 15 | def my_s4 16 | return "my String" 17 | end 18 | 19 | def my_s5 20 | s = "my String" 21 | end 22 | 23 | puts my_s1 24 | puts my_s2 25 | puts my_s3 26 | puts my_s4 27 | puts my_s5 28 | -------------------------------------------------------------------------------- /lecture_code/ruby/oop.rb: -------------------------------------------------------------------------------- 1 | class Square 2 | @@pop = 0 3 | 4 | def initialize(size) 5 | @size = size 6 | @@pop +=1 7 | end 8 | 9 | def area 10 | @size*@size 11 | end 12 | 13 | def pop 14 | @@pop 15 | end 16 | end 17 | 18 | a = Square.new(5) 19 | b = Square.new(6) 20 | 21 | puts a.area 22 | puts b.area 23 | 24 | puts a.pop 25 | -------------------------------------------------------------------------------- /lecture_code/ruby/regex/file.rb: -------------------------------------------------------------------------------- 1 | f = File.open("file2.txt") 2 | regex = /^([A-Z][a-z0-9]+): ([0-9]{3})-([0-9]{3})-([0-9]{4})$/ 3 | phonebook = {} 4 | line = f.gets 5 | while line 6 | if line =~ regex 7 | phonebook[$1] = $2+$3+$4 8 | end 9 | line = f.gets 10 | end 11 | f.close 12 | puts phonebook 13 | puts phonebook.values 14 | puts phonebook.keys 15 | puts phonebook["Name2"] 16 | -------------------------------------------------------------------------------- /lecture_code/ruby/regex/file.txt: -------------------------------------------------------------------------------- 1 | helloooooo 2 | heellohelloheeeeeello 3 | hell 4 | a 5 | b 6 | c 7 | d 8 | e 9 | f 10 | g 11 | h 12 | i 13 | j 14 | A 15 | B 16 | C 17 | D 18 | E 19 | F 20 | G 21 | H 22 | 1 23 | 2 24 | 3 25 | 4 26 | 5 27 | 6 28 | 7 29 | 8 30 | 9 31 | 0 32 | 12 33 | 21 34 | 312 35 | 123 36 | 453 37 | 213 38 | 132 39 | 07 40 | 81 41 | 42 | 90 43 | 121212 44 | _ 45 | cliff 46 | kliff 47 | k 48 | 2+2 49 | 1+5 50 | ^ 51 | aa 52 | 0a0 53 | 1A0 54 | 1 2 55 | 4?4 56 | 3-7 57 | hello 58 | hellohello 59 | hellohellohello 60 | hellhellhellooohello 61 | 3--7 62 | bb 63 | Ab 64 | A0 65 | B2 66 | bA 67 | AA 68 | -------------------------------------------------------------------------------- /lecture_code/ruby/regex/file2.txt: -------------------------------------------------------------------------------- 1 | Person1: 123-456-7890 2 | Name2: 123-456-7890 3 | H12: 567-342-3544 4 | ------------- invalid 5 | +2 (123)4567890 6 | +1 1234567890 7 | +15 1234567890 8 | (123)4567890 9 | )123)4352344 10 | 234--233-2345 11 | (123-456-7890 12 | 123)-456-7890 13 | -------------------------------------------------------------------------------- /lecture_code/ruby/regex/file3.txt: -------------------------------------------------------------------------------- 1 | yellow 2 | red 3 | blue 4 | -------------------------------------------------------------------------------- /lecture_code/ruby/typing.rb: -------------------------------------------------------------------------------- 1 | y = hello 2 | y = 3 3 | z = 4 4 | puts y + z 5 | 6 | y = hello 7 | z = 4 8 | puts y + z 9 | -------------------------------------------------------------------------------- /lecture_code/rust/fact.rs: -------------------------------------------------------------------------------- 1 | fn fact(n:u32) -> u32{ 2 | let mut x = n; 3 | let mut a = 1; 4 | 5 | loop { 6 | if x <= 1 {break;} 7 | a = x * a; 8 | x = x -1; 9 | } 10 | a 11 | } 12 | -------------------------------------------------------------------------------- /lecture_code/rust/factorial.rs: -------------------------------------------------------------------------------- 1 | fn fact(n:i32) -> i32{ 2 | if n == 0 3 | {1} 4 | else 5 | { let x = fact(n-1); 6 | x * n 7 | } 8 | } 9 | 10 | fn main(){ 11 | let res = fact(6); 12 | println!("Fact(6) = {}",res); 13 | } 14 | -------------------------------------------------------------------------------- /lecture_code/rust/lec1: -------------------------------------------------------------------------------- 1 | Rust 2 | 3 | Rust exists to solve memory safety issues that C has 4 | 5 | We want to avoid things like dangling pointers, double free, 6 | data races 7 | 8 | syntax-wise pull from C and ocaml 9 | 10 | // int fact(int n){...} 11 | fn fact(n:i32) -> i32{ 12 | if n == 0 13 | {1} 14 | else 15 | { 16 | let x = fact(n-1); 17 | x * n 18 | } 19 | } 20 | 21 | fn main(){ 22 | let res = fact(6); 23 | println!("fact(6) = {}",res) 24 | } 25 | 26 | let rec fact n = 27 | if n = 0 then 1 else let x = fact (n-1) in x * n 28 | 29 | BLOCKS 30 | By default, things are immutable in Rust 31 | 32 | {stmt* e?} 33 | {1} 34 | {let x = 3; x} 35 | 36 | let x = x + 1; 37 | 38 | {} 39 | 40 | What do the following blocks evaluate to? 41 | {let x = 37; 42 | let y = x + 5; 43 | y; 44 | } 45 | 46 | {let x:u32 = -1; <- rust will yell at you 47 | let y = x + 5; 48 | y 49 | } 50 | 51 | {let x = 3; 52 | x = x + 5; <- rust will yell at you 53 | x 54 | } 55 | 56 | {let x = 3; 57 | let x = x + 5; 58 | x 59 | } 60 | 61 | { let mut x = 3; 62 | x = x + 5; 63 | x 64 | } 65 | 66 | {if n ==0 67 | {1} 68 | else 69 | { let x = 3; 70 | let y = x + 5; 71 | y; 72 | } 73 | } 74 | 75 | if n == 0 76 | {let x = 4;x} 77 | else 78 | {} 79 | 80 | fn name(params) [-> t] { 81 | {} 82 | } 83 | params: x1:t1, x2:t2,.... 84 | 85 | scalar (flat) types 86 | integers: i8, i16, i32, i64, isize (sizeof(int)) 87 | unsigned: u8, u16, u32, u64, usize 88 | char: unicode character 89 | boolean: true, false 90 | float: f32, f64 91 | 92 | structured type 93 | tuples: (t1,t2,t3,..),(e1,e2,e3,...), () 94 | strings: "hello there", "general kenobi" 95 | arrays: constant length, n:[i32], x:[i16,6] 96 | vector: varaible length 97 | fn sort(x:[i32,8]) -> [i32,8] 98 | 99 | pattern matching is supported 100 | 101 | loop {} 102 | while e {} 103 | for pattern in e {} 104 | 105 | fn fact(n:u32) -> u32{ 106 | let mut x = n; 107 | let mut a = 1; 108 | loop { 109 | if x <= 1 {break;} 110 | a = a * x; 111 | x = x - 1; 112 | } 113 | a 114 | } 115 | 116 | fn fact(n:u32) -> u32{ 117 | let mut x = n; 118 | let mut a = 1; 119 | while x > 1{ 120 | a = a * x; 121 | x = x - 1; 122 | } 123 | a 124 | } 125 | 126 | for pattern in e {} 127 | //fn distance((ax,ay):(f64,f64),(bx,by):(f64,f64)) -> f64 { 128 | fn distance(a:(f64,f64),b:(f64,f64)) -> f64 { 129 | let (ax,ay) = a; 130 | let bx = b.0; 131 | let by = b.1; 132 | let dx = ax - bx; 133 | let dy = ay - by; 134 | 135 | (dx * dx + dy * dy).sqrt() 136 | } 137 | 138 | let num = [10;20;30]; 139 | for item in num.iter(){ 140 | println!("the element is {}", item); 141 | } 142 | -------------------------------------------------------------------------------- /lecture_code/rust/lec2: -------------------------------------------------------------------------------- 1 | RUST 2 | 3 | Rust exists to solve memery safety issues that c has 4 | 5 | Rust wants to avoid things like dangling pointers, double fees, 6 | data races 7 | 8 | fn fact(n:i32) -> i32 { 9 | if n == 0 10 | {1} 11 | else 12 | { 13 | let x = fact(n-1); 14 | x * n 15 | } 16 | } 17 | 18 | fn main(){ 19 | let res = fact(6); 20 | println!("fact(6) = {}",res); 21 | } 22 | 23 | let rec fact n = 24 | if n = 0 then 1 25 | else let x = fact (n-1) in x * n 26 | 27 | By default, things are immutable in rust 28 | 29 | BLOCK 30 | let x = { stmt* e?} 31 | {} 32 | {let x = 5;} 33 | 34 | if e 35 | b 36 | 37 | is syntatic sugar of 38 | if e 39 | b:() unit 40 | else 41 | {} 42 | 43 | {if e 44 | b1 45 | else 46 | b2} 47 | 48 | {let x = 37; 49 | let y = 5; 50 | y 51 | } 52 | 53 | {let x:u32 = -1; <- rust will throw an tantrum 54 | x 55 | } 56 | 57 | { let x = 3; <- rust will yell at you 58 | x = x + 1; 59 | x 60 | } 61 | 62 | { let mut x = 3; 63 | x = x + 1; 64 | x 65 | } 66 | 67 | { let x = 3; 68 | let x = x + 1; 69 | x 70 | } 71 | 72 | int myfunc(int x, float y, boolean z){...} 73 | fn myfunc(x:i32, y:f32, z:boolean) -> i32 {...} 74 | fn myfunc(params) -> t { 75 | 76 | } 77 | params: x1:t1,x2:t2,x3:t3,... 78 | 79 | if e b1 else b2 80 | 81 | scalar or flat type 82 | integers: i8, i16,i32,i64, isize (sizeof(int)) 83 | unsigned: u8, u16, u32, u64, usize 84 | chars: unicode character 85 | booleans: true, false 86 | floats: f32, f64 87 | 88 | structured types 89 | tuples: (e1,e2) (t1,t2) x:(f32,f32), y:(boolean,i32,i8) 90 | strings: "hello there", "general kenobi" 91 | arrays: they have constant length, x:[i32], y:[i32,7] 92 | let mut x = [10;20;30]; mutability refers to values in array, not array length 93 | vectors/slices: can have variable length 94 | 95 | loop {...} 96 | while e {...} 97 | for pattern in e {...} 98 | 99 | fn fact(n:u32) -> u32{ 100 | let mut x = n; 101 | let mut a = 1; 102 | loop{ 103 | if x <= 1 {break;} 104 | a = a * x; 105 | x = x - 1; 106 | } 107 | a 108 | } 109 | 110 | 111 | fn fact(n:u32) -> u32{ 112 | let mut x = n; 113 | let mut a = 1; 114 | while x > 1{ 115 | a = a * x; 116 | x = x - 1; 117 | } 118 | a 119 | } 120 | 121 | 122 | 123 | fn distance(a:(f32,f32),b:(f32,f32)) -> f32{ 124 | let (ax,ay) = a; 125 | let bx = b.0; 126 | let by = b.1; 127 | 128 | let dx = ax - bx; 129 | let dy = ay - by; 130 | 131 | (dx*dx - dy * dy).sqrt() 132 | } 133 | 134 | for item in [10;20;30].iter(){ 135 | println!("item is {}", item) 136 | } 137 | -------------------------------------------------------------------------------- /lecture_code/rust/lec3: -------------------------------------------------------------------------------- 1 | RUST 2 | 3 | Rust aims or exists to solve memory safety issues that C has 4 | java, ruby, ocaml, 5 | 6 | rust 7 | ----------C 8 | asm 9 | 10 | avoid things like dangling pointers, double free, data races 11 | 12 | BLOCKS 13 | let z = {stmt* e?} 14 | {} 15 | {let x = 3;} 16 | 17 | if n ==0 18 | {1} 19 | else 20 | {let x = fact(n-1); 21 | x *n 22 | } 23 | 24 | if n == 0 25 | {let a = 3;} 26 | 27 | this is syntatic sugar of 28 | 29 | if n == 0 30 | {let a = 3;} 31 | else 32 | {} 33 | 34 | 35 | by default, things in rust are immutatable 36 | { let x = 37; 37 | let y = x + 5; 38 | y 39 | } 40 | 41 | {let x = 37; 42 | x = x + 5; <- rust will yell at you 43 | x 44 | } 45 | 46 | { let x = 37; 47 | let x = x + 5; 48 | x 49 | } 50 | 51 | { let mut x = 37; 52 | x = x + 5; 53 | x 54 | } 55 | 56 | { let x:u32 = -1; <- rust will throw a tantrum 57 | x 58 | } 59 | 60 | fn name(params) -> t { 61 | 62 | } 63 | params: x1:t1,x2:t2,x3:t3,... 64 | 65 | if e b1 else b2 66 | 67 | scalar or flat types 68 | integers: i8,i16,i32,i64, isize (sizeof(int)) 69 | unsigned: u8, u16, u32, u64, usize 70 | chars: unicode character 71 | booleans: true,false 72 | floats: f32, f64 73 | 74 | structured types 75 | tuples: (3,true), (4,3), (isize,boolean), () 76 | strings: "hello there", "general kenobi" 77 | arrays: constant length 78 | [10,20,30]: [i32] 79 | [10,20,30]: [i32,3] 80 | 81 | loops: 82 | loop {} : run infinite until break 83 | while e {} 84 | 85 | 86 | 87 | for pattern in e {} 88 | //fn distance((ax,ay):(f32,f32),(bx,by):(f32,f32)) -> f32{ 89 | fn distance(a:(f32,f32),b:(f32,f32)) -> f32{ 90 | let (ax,ay) = a; 91 | let bx = b.0; 92 | let by = b.1; 93 | 94 | dx = ax - bx; 95 | dy = ay - by; 96 | 97 | (dx *dx - dy*dy).sqrt() 98 | } 99 | 100 | let nums = [10,20,30]; 101 | for item in nums.iter(){ 102 | println!("item is {}", item); 103 | } 104 | for (ax,bx) in [(12,23)].iter(){ 105 | 106 | } 107 | 108 | -------------------------------------------------------------------------------- /projects/project1b/README.md: -------------------------------------------------------------------------------- 1 | # Project 1b: Translator 2 | 3 | Due: February 19, 2023 at 11:59 PM (late February 20, *10% penalty*). 4 | 5 | **Test Weightage:** 6 | - Public: 50% 7 | - Semipublic: 40% 8 | - Secret: 10% 9 | 10 | **This is an individual assignment. You must work on this project alone.** 11 | 12 | ## Introduction 13 | 14 | In this project, you will be making a simple translator for very simple sentences. 15 | To begin, we have a few things to mention. 16 | Languages have these things called grammars. They define the structure of 17 | a sentence. We will talk more about grammars later in the course but for now 18 | just consider the following: 19 | ```text 20 | Adjective Adjective Noun Verb Adverb 21 | ``` 22 | Choose any two adjective, any noun, verb and adverb and mad-lib (substitute it) 23 | in. You will get a grammatically correct sentence. 24 | ```text 25 | large green trucks stop instantly 26 | poisonous feral moose age rapidly 27 | colourless green ideas sleep furiously 28 | ``` 29 | Notice that grammatically correct does not mean makes sense. 30 | 31 | Adjectives, nouns, verbs, adverbs, etc are referred to as parts of speech. 32 | 33 | For part 1 of this project, you will read in some files that describe various 34 | languages' grammar and lexicon (the words that exist in that language). 35 | 36 | ### **File Inputs** 37 | 38 | You will read in two files. 39 | 40 | #### Language File 41 | First, a file that has a list of words, their part of speech, and their counterpart in other languages. 42 | 43 | The file would have the structure below: 44 | ``` 45 | word, POS, :, :, ... 46 | ``` 47 | * Each starting `word` will be considered part of the `English` language. 48 | * `word` will be at least one character long 49 | * valid characters in `word` are lowercase alphabetic characters and the hyphen character ("-") 50 | * `POS` is the part of speech 51 | * a valid `POS` will be any capitalized 3 letter code: ADJ, NOU, ADV, etc. 52 | * `LX` is a language name (not including `English`) 53 | * A language `LX` starts with a capital letter, and is followed by any number of lowercase alphanumeric characters. 54 | * `wordX` represents `word`'s equivalent in language `LX` 55 | * `wordX` will be a string consisting of lowercase alphabetic characters and the hyphen character ("-") 56 | * `wordX` will be at least one character long 57 | 58 | For example: 59 | ``` 60 | blue, ADJ, French:bleu, German:blau, Spanish:azul, Swedish:bla 61 | truck, NOU, Spanish:camion, German:lkw 62 | the, DET, German:der, Spanish:el, French:le 63 | ``` 64 | 65 | Not all words will have translations to all other languages. 66 | It is also important to note, that some words have multiple parts of speech. 67 | (eg. "Bank" is both a noun and a verb). If this is the case, they will be on seperate lines 68 | ``` 69 | bank, NOU, Spanish:banco 70 | bank, VER, Spanish:ladear 71 | ``` 72 | 73 | If a line doesn't match all the above specifications, ignore the entire line. 74 | 75 | #### Grammar File 76 | Second, a file that describes the grammar structure of a language: 77 | 78 | The file will have the following format 79 | ``` 80 | Lang: POSX1, POSX2, POSX3, ... 81 | ``` 82 | 83 | We will be using similar formatting as the Language File with a slight modification. 84 | * `Lang` is a language name 85 | * A language `Lang` starts with a capital letter, and is followed by any number of lowercase alphanumeric characters. 86 | * `POSXY` denotes a single or repeated `POS` 87 | * a valid `POSXY` will be any capitalized 3 letter code: ADJ, NOU, ADV, etc, with an optional modifier denoting how many times it repeats in a row. 88 | * A valid modifier looks like `{#}` where `#` is any valid Natural number greater than zero. 89 | 90 | For example: 91 | ``` 92 | Language: DET, ADJ{3}, NOU 93 | English: DET, ADJ, NOU 94 | Spanish: DET, NOU, ADJ 95 | Swedish: DET, NOU 96 | French: DET, NOU 97 | German: DET, ADJ, ADJ, NOU, ADJ 98 | ``` 99 | 100 | Each language will only have one grammar structure at a time. 101 | 102 | If a line doesn't match all the above specifications, ignore the entire line. 103 | 104 | ### **Translator Class** 105 | 106 | You will make a `Translator` class which will hold all the words and grammars the translator will know. 107 | When you make a new `Translator`, an initial words and grammar file will be 108 | provided. 109 | 110 | You will need to design a data structure to hold all the information needed. We _highly_ recommend that you make inner classes to store the information in a more concise way. 111 | 112 | #### **Part 1** 113 | 114 | First initialize your data structure and then complete the following methods to add any new words/grammars to your structure. 115 | 116 | - `updateLexicon(inputfile)`: Update the words in your lexicon, by reading in 117 | the file. If you have already seen a word, update your data structure so that any additional 118 | translations are added. 119 | Ignore any malformed lines that do not follow the above formatting. You can assume that the inputfile is a valid file name. 120 | 121 | - `updateGrammar(inputfile)`: Update your grammar knowledge by reading in the 122 | file. If you have already seen a language's grammatical structure, update it 123 | with the new data. Ignore any malformed lines that do not follow the above formatting. You can assume that the inputfile is a valid file name. 124 | 125 | #### **Part 2** 126 | 127 | Here is a grammar structure of a valid English sentence: 128 | ```text 129 | determiner adjective noun 130 | the red truck 131 | a small snail 132 | their cute dog 133 | ``` 134 | However, as you may have noticed in part 1, other languages have different grammar structures. Here is an example 135 | for Spanish sentences: 136 | ``` 137 | determiner noun adjective 138 | el camion rojo 139 | un pequeño caracol 140 | su lindo perro 141 | ``` 142 | 143 | The next few methods rely on the grammatical structures of languages or the grammatical structures that are passed in. 144 | 145 | - `generateSentence(language, struct)`: `struct` is either a grammar, or an array of POS. Given this structure, create a sentence in the given language that 146 | matches that structure. If you cannot, return `nil`. 147 | When multiple POS exist, you can choose any word that has that POS. 148 | Using the sample files shown in the **File Inputs** section, the following examples are provided: 149 | + example: `generateSentence("French", "English")` -> `nil` (*Note: There are no French nouns*) 150 | + example: `generateSentence("German", ["NOU", "DET", "ADJ"])` -> `"der blau lkw"` 151 | + example: `generateSentence("Swedish", ["ADJ"])` -> `"bla"` 152 | + example: `generateSentence("English", "English")` -> `"the blue truck"` 153 | 154 | - `checkGrammar(sentence, language)`: `language` is a language name. Check if the sentence matches that language's grammatical structure and return true or false. You may assume that `sentence` is in `language`'s language. 155 | + example: `checkGrammar("el camion azul", "Spanish")` -> true 156 | + example: `checkGrammar("le bleu", "Swedish")` -> false 157 | 158 | - `changeGrammar(sentence, struct1, struct2)`: `struct1` is either a language name, or an array of POS. `struct2` is either a language name or a array of POS. 159 | Given a sentence and its structure (`struct1`), change the sentence to match `struct2`. 160 | This should work independently of that actual gramatical structure of `sentence` and if the words in `sentence` are actual words or not. You may assume `sentence.length == struct1.length == struct2.length`. 161 | When multiple POS exist, you can swap the order however you want as long as your resuling sentence has all the same words in the input. 162 | If you cannot change the structure, then return `nil`. 163 | + example: `changeGrammar("el azul camion", "English", "Spanish")`-> `"el camion azul"` 164 | + example: `changeGrammar("the blue truck", "English", "English")` -> `"the blue truck"` 165 | + example: `changeGrammar("le bleu", "Swedish", ["ADJ", "DET"])` -> `"bleu le"` 166 | 167 | #### **Part 3** 168 | 169 | Now that we can change the structure of a sentence around, let's now change it syntacitcally. 170 | 171 | That is 172 | ```text 173 | the truck blue -> el camion azul 174 | ``` 175 | The last two methods deal with translating words and also changing the grammar of the sentence. 176 | 177 | - `changeLanguage(sentence, language1, language2)`: 178 | Given a sentence `sentence` that matched the gramatical structure of `language1`, convert the 179 | entire sentence into the target language, `language2`, keeping the same grammatical structure. 180 | If any part of the sentence cannot be translated, then return `nil`. Otherwise return the translated sentence. 181 | You may assume that each word in `sentence` is in `language1`. 182 | + `changeLanguage("i like cheese", "English", "French")` -> `"je aime fromage"` 183 | + `changeLanguage("azul le camion", "Spanish", "German")` -> `"blau der lkw"` 184 | 185 | - `translate(sentence, language1, language2)`: 186 | Given a sentence that matches the gramtical structure of `language1`, convert the entire sentence into the target language, `language2`, and change the grammatical structure to match `language2`. 187 | If any part of the sentence cannot be translated, then return `nil`. Otherwise return the translated sentence. 188 | + example: `translate("the blue truck", "English", "Spanish")` -> `"el camion azul"` 189 | + example: `translate("el camion azul", "Spanish", "English")` -> `"the blue truck"` 190 | -------------------------------------------------------------------------------- /projects/project1b/test/public/inputs/grammar1.txt: -------------------------------------------------------------------------------- 1 | Spanish: DET, NOU, DET 2 | English: DET, ADJ, NOU 3 | German: NOU, ADJ 4 | French: ADJ, NOU, DET 5 | invalid grammar line -------------------------------------------------------------------------------- /projects/project1b/test/public/inputs/grammar2.txt: -------------------------------------------------------------------------------- 1 | L1: NOU, AJD, JKJ 2 | L2: JKJ{2}, NOU, AJD 3 | L3: JKJ{2}, AJD, NOU 4 | L4: AJD, NOU, JKJ 5 | English: NOU, AJD, JKJ -------------------------------------------------------------------------------- /projects/project1b/test/public/inputs/grammar3.txt: -------------------------------------------------------------------------------- 1 | Spanish: DET, NOU, DET 2 | English: DET, ADJ, NOU 3 | German: nou, ADJ 4 | French: ADJ, NOU, DET 5 | -------------------------------------------------------------------------------- /projects/project1b/test/public/inputs/words1.txt: -------------------------------------------------------------------------------- 1 | blue, ADJ, French:bleu, German:blau, Spanish:azul, Swedish:bla 2 | this is an invalid line 3 | truck, NOU, Spanish:camion, German:lkw 4 | the, DET, German:der, Spanish:el, French:le 5 | red, ADJ, French:rouge, German:rot, Spanish:rojo 6 | at, PRE, German:bei 7 | this is also invalid 8 | sea, NOU, German:meer, French:mer 9 | fork, NOU, Italian:forchetta, German:gabel 10 | -------------------------------------------------------------------------------- /projects/project1b/test/public/inputs/words2.txt: -------------------------------------------------------------------------------- 1 | w-one, AJD, L1:w-two, L2:w-three, L3:w-four, L4:w-five 2 | w-ten, AJD, L2:w-oneone, L3:w-onetwo, L2:w-onethree, L3:w-onetwo 3 | w-onefour, JKJ, L4:w-onefive, L2:w-onesix, L1:w-oneseven, L3:w-oneeight 4 | w-six, JKJ, L1:w-seven, L4:w-eight, L2:w-nine 5 | w-onenine, NOU, L1:w-twozero, L2:w-twoone, L3:w-twotwo, L4:w-twothree 6 | w-twofour, NOU, L1:w-twofive, L2:w-twosix, L3:w-twoseven 7 | w-twoeight, NOU, L1:w-twonine, L3:w-threezero, L4:w-threeone 8 | only one invalid here for good measure -------------------------------------------------------------------------------- /projects/project1b/test/public/inputs/words3.txt: -------------------------------------------------------------------------------- 1 | blue, ADJ, French:bleu, German:blau, Spanish:azul, Swedish:Bla 2 | this is an invalid line 3 | truck, NOU, Spanish:camion, German:lkw 4 | the, DET, German:der, Spanish:el, French: 5 | red, ADJ, French:rouge, German:rot, Spanish:rojo 6 | at, PRE, German:bei 7 | this is also invalid 8 | sea, NOU, German:meer, French:mer 9 | fork, NOU, Italian:forchetta, German:gabel 10 | -------------------------------------------------------------------------------- /projects/project1b/test/public/public.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | require_relative "../../src/translate.rb" 3 | 4 | # This is how you can load in files for testing 5 | WORDS_FILE1 = "#{__dir__}/inputs/words1.txt" 6 | GRAMMAR_FILE1 = "#{__dir__}/inputs/grammar1.txt" 7 | WORDS_FILE2 = "#{__dir__}/inputs/words2.txt" 8 | GRAMMAR_FILE2 = "#{__dir__}/inputs/grammar2.txt" 9 | WORDS_FILE3 = "#{__dir__}/inputs/words3.txt" 10 | GRAMMAR_FILE3 = "#{__dir__}/inputs/grammar3.txt" 11 | 12 | 13 | class PublicTests 'c * 'b * 'a` 67 | - **Description**: Returns a 3-tuple in the reverse order of `tup`. 68 | - **Examples**: 69 | ```ocaml 70 | rev_tup (1, 2, 3) = (3, 2, 1) 71 | rev_tup (1, 1, 1) = (1, 1, 1) 72 | rev_tup ("a", 1, "c") = ("c", 1, "a") 73 | ``` 74 | 75 | #### `is_even x` 76 | 77 | - **Type**: `int -> bool` 78 | - **Description**: Returns whether or not `x` is even. 79 | - **Examples**: 80 | ```ocaml 81 | is_even 1 = false 82 | is_even 4 = true 83 | is_even (-5) = false 84 | ``` 85 | 86 | #### `area p q` 87 | 88 | - **Type**: `int * int -> int * int -> int` 89 | - **Description**: Takes in the Cartesian coordinates (2-dimensional) of any pair of opposite corners of a rectangle and returns the area of the rectangle. The sides of the rectangle are parallel to the axes. 90 | - **Examples**: 91 | ```ocaml 92 | area (1, 1) (2, 2) = 1 93 | area (2, 2) (1, 1) = 1 94 | area (2, 1) (1, 2) = 1 95 | area (0, 1) (2, 3) = 4 96 | area (1, 1) (1, 1) = 0 97 | area ((-1), (-1)) (1, 1) = 4 98 | ``` 99 | 100 | # Part 2: Recursive Functions 101 | 102 | Implement the following functions using recursion. You will lose points if this rule is not followed. 103 | If you create a recursive helper function, the main function that calls the recursive helper does not have to be recursive/have the `rec` keyword in its function header. 104 | 105 | #### `fibonacci n` 106 | 107 | - **Type**: `int -> int` 108 | - **Description**: Returns the `n`th term of the fibonacci sequence. 109 | - **Assumptions**: `n` is non-negative, and we will **not** test your code for integer overflow cases. 110 | - **Examples**: 111 | ```ocaml 112 | fibonacci 0 = 0 113 | fibonacci 1 = 1 114 | fibonacci 3 = 2 115 | fibonacci 6 = 8 116 | ``` 117 | 118 | #### `pow x p` 119 | 120 | - **Type**: `int -> int -> int` 121 | - **Description**: Returns `x` raised to the power `p`. 122 | - **Assumptions**: `p` is non-negative, and we will **not** test your code for integer overflow cases. 123 | - **Examples**: 124 | ```ocaml 125 | pow 3 1 = 3 126 | pow 3 2 = 9 127 | pow (-3) 3 = -27 128 | ``` 129 | 130 | #### `is_prime x` 131 | - **Type**: `int -> bool` 132 | - **Description**: Returns whether or not `x` is prime. Note that all negative numbers are non-prime. 133 | - **Examples**: 134 | ``` ocaml 135 | is_prime 1 = false 136 | is_prime 2 = true 137 | is_prime 3 = true 138 | is_prime 4 = false 139 | is_prime 5 = true 140 | is_prime 60 = false 141 | is_prime 61 = true 142 | is_prime (-2) = false 143 | ``` 144 | 145 | #### `maxFuncChain init funcs` 146 | - **Description**: MaxProcChain from Project 1a makes its return, OCaml style! This function takes in an initial value and a list of functions, and decides to either apply each function or not to maximize the final return value. For example, if I have a list of functions: 147 | `[funcA; funcB; funcC]` and an initial value `x`, then I take the maximum value 148 | of 149 | + `x` 150 | + `funcA(x)` 151 | + `funcB(funcA(x))` 152 | + `funcC(funcB(funcA(x)))` 153 | + `funcC(funcA(x))` 154 | + `funcB(x)` 155 | + `funcC(funcB(x))` 156 | + `funcC(x)` 157 | 158 | - **Type**: `'a -> ('a -> 'a) list -> 'a` 159 | - **Examples**: 160 | ```ocaml 161 | maxFuncChain 2 [(fun x -> x + 6)] = 8 162 | maxFuncChain 2 [(fun x -> x + 4); (fun x -> x * 4)] = 24 163 | maxFuncChain 4 [(fun x -> x - 2); (fun x -> x + 10)] = 14 164 | maxFuncChain 0 [(fun x -> x - 1); (fun x -> x * -500); (fun x -> x + 1)] = 501 165 | maxFuncChain "hello" [(fun x -> x ^ "1"); (fun x -> x ^ "2"); (fun x -> x ^ "3")] = "hello3" 166 | ``` 167 | 168 | # Part 3: Lists 169 | 170 | These may be implemented recursively, but it is not required. 171 | 172 | #### `reverse lst` 173 | 174 | - **Type**: `'a list -> 'a list` 175 | - **Description**: Returns a list with the elements of `lst` but in reverse order. 176 | - **Examples**: 177 | ```ocaml 178 | reverse [] = [] 179 | reverse [1] = [1] 180 | reverse [1; 2; 3] = [3; 2; 1] 181 | reverse ["a"; "b"; "c"] = ["c"; "b"; "a"] 182 | ``` 183 | 184 | #### `merge lst1 lst2` 185 | 186 | - **Type**: `'a list -> 'a list -> 'a list` 187 | - **Description**: Merge two sorted lists, `lst1` and `lst2`, and return the result as a sorted list. 188 | - **Examples**: 189 | ```ocaml 190 | merge [1] [2] = [1;2] 191 | merge [] [] = [] 192 | merge [1; 4] [2; 3] = [1; 2; 3; 4] 193 | merge [1; 4; 5] [2; 3; 6; 7; 8; 9] = [1; 2; 3; 4; 5; 6; 7; 8; 9] 194 | merge [1] [0] = [0; 1] 195 | ``` 196 | 197 | #### `jumping_tuples lst1 lst2` 198 | 199 | - **Type**: `('a * 'b) list -> ('c * 'a) list -> 'a list` 200 | - **Description**: Given two lists of two element tuples, `lst1` and `lst2`, returns a list with the first element of every odd indexed tuple in `lst1`, and the second element of every even indexed tuple in `lst2`, interwoven together (starting from index 0). For this function, consider 0 as even. If the lists are not the same length, the resulting list should have the length of the shorter of the input lists. 201 | - **Examples**: 202 | ```ocaml 203 | jumping_tuples [(1, 2); (3, 4); (5, 6)] [(7, 8); (9, 10); (11, 12)] = [8; 3; 12] 204 | jumping_tuples [(true,"a"); (false,"b")] [(100, false)] = [false] 205 | jumping_tuples [("first", "second"); ("third", "fourth")] [("fifth", "sixth"); ("seventh", "eighth")] = ["sixth"; "third"] 206 | jumping_tuples [] [] = [] 207 | ``` 208 | 209 | #### `is_palindrome lst` 210 | 211 | - **Type**: `'a list -> bool` 212 | - **Description**: Returns true if `lst` is a palindrome and returns false otherwise. A palindrome is the same read forward and backward. 213 | - **Important Note**: Use wildcards `_` to make sure all match cases are exhaustive. 214 | - **Examples**: 215 | ```ocaml 216 | is_palindrome [] = true 217 | is_palindrome [1; 2; 3; 2; 1] = true 218 | is_palindrome ["A"; "b"; "b"; "A"] = true 219 | is_palindrome ["O"; "C"; "A"; "M"; "L"] = false 220 | ``` 221 | 222 | #### `square_primes lst` 223 | 224 | - **Type**: `int list -> (int * int) list` 225 | - **Description**: Returns a list of tuples `(a, b)` in which `a` is a prime number from `lst` and `b` is that prime number squared. If an element in `lst` is not a prime number, ignore it. 226 | - **Examples**: 227 | ```ocaml 228 | square_primes [1; 2; 3; 4; 5] = [(2, 4); (3, 9); (5, 25)] 229 | square_primes [10; 11; 12; 13; 14] = [(11, 121); (13, 169)] 230 | square_primes [4; 6; 8] = [] 231 | ``` 232 | 233 | #### `flatten lst` 234 | 235 | - **Type**: `'a list list -> 'a list` 236 | - **Description**: Returns a combined list of all of the lists in `lst`. Make sure the original ordering of the lists in `lst` is preserved. 237 | - **Examples**: 238 | ```ocaml 239 | flatten [[1; 2; 3; 4]; [5; 6]] = [1; 2; 3; 4; 5; 6] 240 | flatten [[6]; [5]; [4]; [3]; [2]; [1]] = [6; 5; 4; 3; 2; 1] 241 | flatten [[1; 2]; [3; 4]; []] = [1; 2; 3; 4] 242 | flatten [[1]; [2]; [3]] = [1; 2; 3] 243 | ``` 244 | 245 | #### `partition p lst` 246 | 247 | - **Type**: `('a -> bool) -> 'a list -> 'a list * 'a list` 248 | - **Description**: Returns a tuple of lists `(l1, l2)`, where `l1` is a list of all elements in `lst` that satisfy the predicate `p`, and `l2` is a list of all elements in `lst` that don’t satisfy the predicate `p`. 249 | - **Examples**: 250 | ```ocaml 251 | partition is_prime [1; 2; 3; 4; 5] = ([2; 3; 5], [1; 4]) 252 | partition is_prime [10; 12; 14] = ([], [10; 12; 14]) 253 | partition is_even [1; 2; 3; 4; 5] = ([2; 4], [1; 3; 5]) 254 | ``` 255 | 256 | # Part 4: Higher Order Functions 257 | 258 | Write the following functions using `map`, `fold`, or `fold_right` as defined in the file `funs.ml`. You **must** use `map`, `fold`, or `fold_right` to complete these functions, so none of the functions in Part 4 should be defined using the `rec` keyword. You also may not create recursive helper functions. You will lose points if this rule is not followed. 259 | You are allowed to use previously defined non-recursive functions, but you should not need to. 260 | 261 | #### `is_present lst x` 262 | 263 | - **Type**: `'a list -> 'a -> int list` 264 | - **Description**: Returns a list of the same length as `lst` which has a `1` at each position in which the corresponding position in `lst` is equal to `x`, and a `0` otherwise. 265 | - **Examples**: 266 | ```ocaml 267 | assert(is_present [1;2;3] 1 = [1;0;0]);; 268 | assert(is_present [1;1;0] 0 = [0;0;1]);; 269 | assert(is_present [2;0;2] 2 = [1;0;1]);; 270 | ``` 271 | 272 | #### `count_occ lst target` 273 | 274 | - **Type**: `'a list -> 'a -> int` 275 | - **Description**: Returns how many elements in `lst` are equal to `target`. 276 | - **Examples**: 277 | ```ocaml 278 | assert(count_occ [] 1 = 0);; 279 | assert(count_occ [1] 1 = 1);; 280 | assert(count_occ [1; 2; 2; 1; 3] 1 = 2);; 281 | ``` 282 | 283 | #### `uniq lst` 284 | 285 | - **Type**: `'a list -> 'a list` 286 | - **Description**: Given a list, returns a list with all duplicate elements removed. *Order does not matter, in the output list.* 287 | - **Examples**: 288 | ```ocaml 289 | assert(uniq [] = []);; 290 | assert(uniq [1] = [1]);; 291 | assert(uniq [1; 2; 2; 1; 3] = [2; 1; 3]);; 292 | ``` 293 | 294 | ## Academic Integrity 295 | 296 | Please **carefully read** the academic honesty section of the course syllabus. **Any evidence** of impermissible cooperation on projects, use of disallowed materials or resources, or unauthorized use of computer accounts, **will be** submitted to the Student Honor Council, which could result in an XF for the course, or suspension or expulsion from the University. This includes posting this project to GitHub after the course is over. Be sure you understand what you are and what you are not permitted to do in regards to academic integrity when it comes to project assignments. These policies apply to all students, and the Student Honor Council does not consider lack of knowledge of the policies to be a defense for violating them. Full information is found in the course syllabus, which you should review before starting. 297 | -------------------------------------------------------------------------------- /projects/project2b/GRADESCOPE_SUBMIT.md: -------------------------------------------------------------------------------- 1 | # New Submission prosses 2 | 3 | *Note the new submission process is completely optional and the `gradescope_submit` command from previous projects will continue to work.* 4 | 5 | We are working on a new version of the `gradescope_submit` command and would appreciate student helping us 6 | to test the new process with project 2b. The new submission process is described below. 7 | 8 | ## Installing new command 9 | 10 | To install the new `submit` command complete the following steps: 11 | 12 | 1. Update your `opam` repository by running: `opam update` 13 | 2. Install the new version of submit by running: `opam install gradescope_submit` 14 | 15 | *Note: This will not conflict with the `gradescope_submit` command from previous projects* 16 | 17 | ## Link Github to Gradescope 18 | 19 | Log into your gradescope account and go to your account settings. Scroll down to the `Linked Accounts` section. If you do not already 20 | have your Github account linked here, click the `Link a GitHub account` button and log into your Github account. 21 | 22 | ## Using the new submit command 23 | 24 | First make sure all your changes are pushed to github using the `git add`, `git commit`, and `git push` commands. 25 | 26 | Next, to submit your project using the new submit command you can run `submit` from your project directory. 27 | 28 | The new `submit` comand will pull your code from GitHub, not your local files. If you do not push your changes to GitHub, 29 | they will not be uploaded to gradescope. 30 | -------------------------------------------------------------------------------- /projects/project2b/README.md: -------------------------------------------------------------------------------- 1 | # Project 2b: HOFs on trees & Database design 2 | Due: March 12th 11:59 PM (Late: March 13th 11:59 PM) 3 | 4 | Points: 40% public, 30% semipublic, 30% secret 5 | 6 | **This is an individual assignment. You must work on this project alone.** 7 | 8 | ## Introduction 9 | The goal of this project is to increase your familiarity with programming in OCaml and give you more practice with higher order functions and user-defined types. You will write a number of small functions that will use higher order functions operating over a tree structure, and then you will implement a program that simulates a database. 10 | 11 | ### Ground Rules 12 | In addition to your own code, you may use library functions found in the [`Stdlib` module](https://caml.inria.fr/pub/docs/manual-ocaml/libref/Stdlib.html) and the `List` module. You **may not** (under threat of a grading penalty) use any other submodules of `Stdlib` or any imperative features of Ocaml unless otherwise stated. You **may not** make any function in part 2 recursive unless the function already has the `rec` keyword. 13 | 14 | ### Testing & Submitting 15 | Submit by either running `gradescope-submit` or `submit` (if you have installed the new version of gradescope submit on your computer). 16 | 17 | Instructions to use the new optional submit process can be found [here](./GRADESCOPE_SUBMIT.md) 18 | 19 | To test locally, run `dune runtest -f`. Besides the provided public tests, you will also find the file `student.ml` in `test/student/`, where you'll be able to add `OUnit` tests of your own. More detailed information about writing tests can be found [here](https://www.youtube.com/watch?v=C36JnAcClOQ). 20 | 21 | You can interactively test your code by running `dune utop src`, which will include your source files. (As usual, all of your commands in `utop` need to end with two semicolons (`;;`), otherwise it will appear as if your terminal is hanging) 22 | 23 | ## Part 1: Database Design 24 | 25 | Create a program that stores `person`s in a database which can later be queried. 26 | A person is defined as follows: 27 | 28 | ```ocaml 29 | type person = { name: string; 30 | age: int; 31 | hobbies: string list } 32 | ``` 33 | 34 | You must come up with your own implementation for the data type for the database `db`. As provided above, `person` includes `name`, `age`, and `hobbies`, which is the data we would like to add to our database. 35 | 36 | Given a piece of data like `person`, you will implement the following operations on the database: 37 | 38 | ### `newDatabase` 39 | - **Type**: `db` 40 | - **Description**: creates and returns an empty database 41 | 42 | ### `insert person database`: 43 | - **Type**: `person -> db -> db` 44 | - **Description**: given a person and a database, insert the person into the database and return the updated database. If the person already exists in the database, there should be duplicate entries of the person after performing the insert function. 45 | - **Examples**: 46 | ```ocaml 47 | let db1 = insert {name="Alice";age=23;hobbies=["Skiing";"golfing"]} newDatabase 48 | let db1 = insert {name="Alice";age=23;hobbies=["Skiing";"golfing"]} db1 49 | (* db1 stores a database that includes Alice twice, so querying the size 50 | of this database should result in 2 instances of the Alice person *) 51 | ``` 52 | 53 | ### `remove name database`: 54 | - **Type**: `string -> db -> db` 55 | - **Description**: given a person's name and a database, remove all persons with the same name from the database and return the updated database. If no persons exist in the database with the same name as the given person, the database should not change. 56 | - **Examples**: 57 | ```ocaml 58 | let db1 = remove "Alice" db1 59 | (* db1 no longer contains Alice, db1 is now empty *) 60 | ``` 61 | #### Comparator 62 | A comparator is a function that tells how to compare two people. 63 | Its type is `person -> person -> int`. It follows the typical -1, 0, 1 convention. Below is an example comparator: 64 | ```ocaml 65 | let comparator1 p1 p2 = 66 | if p1.age < p2.age then -1 67 | else if p1.age == p2.age then 0 68 | else 1 69 | ``` 70 | 71 | ### `sort comparator db`: 72 | - **Type**: `(person -> person -> int) -> db -> person list` 73 | - **Description**: given a comparator function and a db, sort the list of people based on the comparator and return in the form of a person list. You may use anything from the `Stdlib` or the `List` modules to help you. 74 | - **Examples**: 75 | ```ocaml 76 | let db1 = insert {name="Alice";age=23;hobbies=["Skiing";"golfing"]} newDatabase 77 | let db2 = insert {name="Bob";age=42;hobbies=["Skiing";"Cooking"; "Legos"]} db1 78 | sort comparator1 db2 = [{name="Alice";age=23;hobbies=["Skiing";"golfing"]}; {name="Bob";age=42;hobbies=["Skiing";"Cooking"; "Legos"]}] 79 | ``` 80 | 81 | #### Aside 82 | 83 | When we are describing something we typically link together and modify different 84 | descriptors with common words like *and*, *or*, *not*. For example: "His name 85 | is Cliff AND he is older than 18 AND (he likes Lego OR he likes chocolate)." 86 | Here I added parenthesis to remove ambiguity. If we changed the syntax of this 87 | sentence we can remove some of the ambiguity: (and his name is cliff, and he is 88 | is older than 18, or he likes Lego, he likes chocolate). Here, while it 89 | looks weird and sounds weird if you were to say it out loud, by defining words 90 | like *and* to link exactly 2 parts together, we can figure out exactly which 91 | parts are conjoined and which are under the *or* condition. 92 | Visually this looks like: 93 | ```text 94 | and(e1,e2) 95 | or(e1,e2) 96 | and(name is cliff,and(older than 18, or(likes Lego, likes Chocolate))) 97 | ``` 98 | 99 | The nice part about this modified English grammar/syntax is that we don't have 100 | ambiguity and it's easy to represent this as code. See below. 101 | 102 | #### Condition 103 | A `condition` is a restriction on the combination of age, name, and/or hobbies. We represent a condition as a type containing either a true/false value, a restriction on age, name, or hobbies, or a logical operator that contains other conditions. The `condition` type will look like this: 104 | ```ocaml 105 | type condition = 106 | | True 107 | | False 108 | | Age of (int -> bool) 109 | | Name of (string -> bool) 110 | | Hobbies of (string list-> bool) 111 | | And of condition * condition 112 | | Or of condition * condition 113 | | Not of condition 114 | | If of condition * condition * condition 115 | ``` 116 | 117 | 118 | Assume that conditions assigned to `True` will always evaluate to `true` and `False` will evaluate to `false`. For example, if I wanted to get a list of people who are over 30 **and** have the name "Bob", our condition would look like this: 119 | ```ocaml 120 | let condition1 = And(Age(fun age -> age > 30), Name(fun name -> name = "Bob"));; 121 | ``` 122 | Other examples of valid `condition`s are: 123 | ```ocaml 124 | False 125 | Name(fun name -> name = "Alice") 126 | Not((Age(fun age -> a < 30))) 127 | If(True,Age(fun age -> a < 30),Name(fun name -> name = "Bob")) 128 | (* if true then Age else Name *) 129 | Or(True,Hobbies(fun hobbies -> false)) 130 | ``` 131 | 132 | 133 | ### `query condition db`: 134 | - **Type**: `condition -> db -> person list` 135 | - **Description**: given a condition and a database, return a list of all entries in the database that satisfy the condition. 136 | - **Examples**: 137 | ```ocaml 138 | query condition1 db2 = [{name="Bob";age=42;hobbies=["Skiing";"Cooking"; "Legos"]}] 139 | (* Order does not matter in this example *) 140 | query True db2 = [{name="Bob";age=42;hobbies=["Skiing";"Cooking"; "Legos"]}; {name="Alice";age=23;hobbies=["Skiing";"golfing"]}] 141 | query False db2 = [] 142 | ``` 143 | 144 | ### `queryBy condition database comparator`: 145 | - **Type**: `condition -> db -> comparator -> person list`: 146 | - **Description**: given a condition, a database, and a comparator, return a list of all entries in the database that satisfy that query that is sorted by the comparator function 147 | - **Examples**: 148 | ```ocaml 149 | condition2 = Age(fun age -> age < 90) 150 | queryBy condition2 db2 comparator1 = [{name="Alice";age=23;hobbies=["Skiing";"golfing"]}; {name="Bob";age=42;hobbies=["Skiing";"Cooking"; "Legos"]}] 151 | ``` 152 | 153 | ### `update condition db personData` 154 | - **Type**: `condition -> db -> (person -> person) -> db` 155 | - **Description**: given a condition, a database, and a function that will return a person with updated data given a person, update every person in the database that satisfies the condition with the given function 156 | - **Examples**: 157 | ```ocaml 158 | let change1 = fun person -> { name = person.name; age = person.age; hobbies = "Pickleball"::person.hobbies} 159 | update condition1 db2 change1 160 | (* Bob's hobbies are now updated to include pickleball *) 161 | ``` 162 | 163 | ### `deleteAll condition db` 164 | - **Type**: `condition -> db -> db` 165 | - **Description**: given a condition and a database, delete all entries 166 | in the database that satisfy the query 167 | - **Examples**: 168 | ```ocaml 169 | deleteAll condition1 db2 170 | (* Bob is deleted from our database *) 171 | ``` 172 | 173 | ## Part 2: Higher Order Functions On Trees 174 | 175 | ***This part is independent of Part 1*** 176 | 177 | Given the type of a binary tree, implement `fold` and `map` operations. 178 | 179 | ```ocaml 180 | type 'a tree = 181 | | Node of 'a tree * 'a * 'a tree 182 | | Leaf 183 | 184 | ``` 185 | 186 | Given this type implement the following functions 187 | 188 | ### `tree_fold f init tree` 189 | - **Type**: `(('a -> 'b -> 'a -> 'a) -> 'a -> 'b tree -> 'a)` 190 | - **Description**: Given a function `f`, accumulator `init`, and `tree`, iterate over the given tree using `f` and return the iterated value of type `'a`. 191 | The function `f` will take in three parameters: the value of the accumulator returned by the left branch of the node, the value of the current node, and the value of the accumulator returned by the right branch of the node, and should then return the new accumulated value of type `'a`. 192 | 193 | - **Examples**: 194 | ```ocaml 195 | let treea = Node(Node(Leaf, "Hello", Leaf), " World", Node(Leaf, "!", Leaf)) in 196 | let treeb = Node(Node(Leaf, 5, Leaf), 6, Leaf) in 197 | 198 | tree_fold (fun l s r -> l ^ s ^ r) "" treea = "Hello World!" 199 | tree_fold (fun l x r -> max (max l x) r) 0 treeb = 6 200 | ``` 201 | 202 | ### `map tree f` 203 | - **Type**: `('a tree -> ('a -> 'b) -> 'b tree)` 204 | - **Description**: Given a function `f`, map all the values of the nodes in the tree using `f`. You must implement this function using `tree_fold`. 205 | Note that the mapped tree should still return the same tree shape with the corresponding mapped nodes. 206 | - **Examples**: 207 | ```ocaml 208 | let treea = Node(Node(Leaf, 1, Leaf), 2, Node(Leaf, 2, Leaf)) in 209 | let treeb = Node(Node(Leaf, 1, Leaf), 2, Node(Node(Leaf, 3, Leaf), 4, Leaf)) in 210 | 211 | map treea string_of_int = Node(Node(Leaf, "1", Leaf), "2", Node(Leaf, "2", Leaf)) 212 | map treeb (fun x -> x + 1) = Node(Node(Leaf, 2, Leaf), 3, Node(Node(Leaf, 4, Leaf), 5, Leaf)) 213 | ``` 214 | 215 | ### `mirror tree` 216 | - **Type**: `('a tree -> 'a tree)` 217 | - **Description**: Write a function using `tree_fold` that will return the given tree with the left and right branches swapped at each node. 218 | - **Examples**: 219 | ```ocaml 220 | let treea = Node(Node(Leaf, 1, Leaf), 2, Node(Leaf, 3, Leaf)) 221 | let treeb = Node(Node(Leaf, 1, Leaf), 2, Node(Node(Leaf, 3, Leaf), 4, Leaf)) 222 | 223 | mirror treea = Node(Node(Leaf, 3, Leaf), 2, Node(Leaf, 1, Leaf)); 224 | mirror treeb = Node(Node(Leaf, 4, Node(Leaf, 3, Leaf)), 2, Node(Leaf, 1, Leaf)) 225 | ``` 226 | 227 | ### `in_order tree` 228 | - **Type**: `('a tree -> 'a list)` 229 | - **Description**: Using `tree_fold`, write a function that will return a list containing the inorder traversal of the tree. 230 | - **Examples**: 231 | ```ocaml 232 | let treea = Node(Node(Leaf, 1, Leaf), 2, Node(Leaf, 3, Leaf)) 233 | let treeb = Node(Node(Leaf, 1, Leaf), 2, Node(Node(Leaf, 3, Leaf), 4, Leaf)) 234 | 235 | in_order treea = [1; 2; 3] 236 | in_order treeb = [1; 2; 3; 4] 237 | ``` 238 | 239 | ### `pre_order tree` 240 | - **Type**: `('a tree -> 'a list)` 241 | - **Description**: Using `tree_fold`, write a function that will return a list containing the preorder traversal of the tree. 242 | - **Examples**: 243 | ```ocaml 244 | let treea = Node(Node(Leaf, 1, Leaf), 2, Node(Leaf, 3, Leaf)) 245 | let treeb = Node(Node(Leaf, 1, Leaf), 2, Node(Node(Leaf, 3, Leaf), 4, Leaf)) 246 | 247 | pre_order treea = [2; 1; 3] 248 | pre_order treeb = [2; 1; 4; 3] 249 | ``` 250 | 251 | ### `compose tree` 252 | - **Type**: `(('a -> 'a) tree -> 'a -> 'a)` 253 | - **Description**: This function will take in a tree that contains `('a -> 'a)` functions as the value in the nodes and returns a function that is the *inorder* composition of the nodes. You must implement this function using `tree_fold`. 254 | - **Examples**: 255 | Consider the following diagram of a tree. 256 | ``` 257 | +------+ 258 | +-------+ f(x) +-------+ 259 | | +------+ | 260 | | | 261 | +--+---+ +---+--+ 262 | +---+ g(x) | +---+ h(x) | 263 | | +------+ | +------+ 264 | | | 265 | +--+---+ +--+---+ 266 | | v(x) | | y(x) | 267 | +------+ +------+ 268 | ``` 269 | The result of calling `compose` on this function would be equivalent to `(fun x -> h (y (f (g (v x)))))` 270 | ```ocaml 271 | let function_tree = 272 | Node( 273 | Node(Leaf, (fun x -> x+1), Leaf), 274 | (fun x -> x*x), 275 | Node(Leaf, (fun x -> -x +x*x), Leaf)) 276 | 277 | let composed = compose function_tree 278 | composed 0 = 0 279 | composed 1 = 12 280 | 281 | let composed2 = compose Leaf 282 | composed2 2 = 2 283 | composed2 15 = 15 284 | ``` 285 | 286 | ### `depth tree` 287 | - **Type**: `('a tree -> int)` 288 | - **Description**: Using `tree_fold` write a function that returns the depth of the deepest node in the tree. 289 | - **Examples**: 290 | ```ocaml 291 | let treea = Node(Node(Leaf, 1, Leaf), 2, Node(Leaf, 3, Leaf)) in 292 | let treeb = Node(Node(Leaf, 1, Leaf), 2, Node(Node(Leaf, 3, Leaf), 4, Leaf)) in 293 | 294 | depth treea = 2 295 | depth treeb = 3 296 | depth Leaf = 0 297 | ``` 298 | 299 | ### `trim tree n` 300 | - **Type**: `('a tree -> int -> 'a tree)` 301 | - **Description**: Using `tree_fold` write a function that takes in a complete binary tree `tree` and an integer `n`, and trims off nodes at the bottom of the tree such that the depth of the returned tree is at most n. 302 | - **Examples**: 303 | ```ocaml 304 | let tree = Node(Node(Node(Leaf, 4, Leaf), 2, Node(Leaf, 4, Leaf)), 1, Node(Node(Leaf, 4, Leaf), 2, Node(Leaf, 4, Leaf))) in 305 | 306 | trim tree 1 = Node(Leaf, 1, Leaf); 307 | trim tree 2 = Node(Node(Leaf, 2, Leaf), 1, Node(Leaf, 2, Leaf)) 308 | ``` 309 | ## Part 3: Generating Trees 310 | #### Options 311 | An `option` type is a built in variant that indicates the presence or absence of a value of type `'a`: 312 | ```ocaml 313 | type 'a option = 314 | | None 315 | | Some of 'a 316 | ``` 317 | 318 | ##### Note: The functions **`tree_init`** and **`split`** are **optional** and will not be tested on, but are recommended helper functions for `from_pre_in`. 319 | ### `tree_init f v` 320 | - **Type**: `('a -> ('a * 'b * 'a) option) -> 'a -> 'b tree)` 321 | - **Description**: A generator `f` is a function that returns a tuple of 3 values: (`v1`, `v2`, `v3`). Using the definition of type `Option`, `f`, and an init value `v`, build a tree that has a root node with value `v2` and a new generated left subtree with init value `v1` and a new generated right subtree with init `v3`. 322 | If `f` returns `None`, a `Leaf` will be placed into the tree. 323 | - **Examples**: 324 | ```ocaml 325 | let generator1 a = 326 | if a <= 3 then 327 | Some (a+1, a, a+1) 328 | else None 329 | 330 | let generator2 a = 331 | if a <= 3 then 332 | Some (a+1, a, a+2) 333 | else None 334 | 335 | tree_init generator1 1 = Node(Node(Node(Leaf, 3, Leaf), 2, Node(Leaf, 3, Leaf)), 1, Node(Node(Leaf, 3, Leaf), 2, Node(Leaf, 3, Leaf))) 336 | tree_init generator2 1 = Node(Node(Node(Leaf, 3, Leaf), 2, Leaf), 1, Node(Leaf, 3, Leaf)) 337 | ``` 338 | 339 | ### `split lst v` 340 | - **Type**: `'a list -> 'a -> 'a list * 'a list` 341 | - **Description**: Given a list `lst` find the first instance of `v` in the list, and return a tuple of lists where the first list in the tuple is all the elements that come before `v` in `lst` and the second element contains all the elements that come after `v` in `lst` 342 | - **Examples**: 343 | ```ocaml 344 | split [1; 2; 3; 4] 2 = ([1]; [3; 4]) 345 | split ["Hello"; "World"] "World" = (["Hello"], []) 346 | ``` 347 | 348 | ### `from_pre_in pre in_ord` 349 | - **Type**: `('a list -> 'a list -> 'a tree)` 350 | - **Description**: Given a list containing the pre-order traversal of a tree `pre` and a list containing the in-order traversal of a tree `in_ord`, create a tree that corresponds to the two traversals. Assume there will be no duplicate nodes in the tree. You may use the algorithm described [here](./from_pre_in.pdf) to implement this function. ***Hint: You can use `tree_init` and `split` in this function*** 351 | - **Examples**: 352 | ```ocaml 353 | let treea = Node(Node(Leaf, 1, Leaf), 2, Node(Leaf, 3, Leaf)) 354 | let treeb = Node(Node(Leaf, 1, Leaf), 2, Node(Node(Leaf, 3, Leaf), 4, Leaf));; 355 | 356 | from_pre_in [2; 1; 3] [1; 2; 3] = treea; 357 | from_pre_in [2; 1; 4; 3] [1; 2; 3; 4] = treeb 358 | ``` 359 | 360 | -------------------------------------------------------------------------------- /projects/project2b/from_pre_in.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/projects/project2b/from_pre_in.pdf -------------------------------------------------------------------------------- /projects/project3/GRADESCOPE_SUBMIT.md: -------------------------------------------------------------------------------- 1 | # New Submission prosses 2 | 3 | *Note the new submission process is completely optional and the `gradescope_submit` command from previous projects will continue to work.* 4 | 5 | We are working on a new version of the `gradescope_submit` command and would appreciate student helping us 6 | to test the new process with project 2b. The new submission process is described below. 7 | 8 | ## Installing new command 9 | 10 | To install the new `submit` command complete the following steps: 11 | 12 | 1. Update your `opam` repository by running: `opam update` 13 | 2. Install the new version of submit by running: `opam install gradescope_submit` 14 | 15 | *Note: This will not conflict with the `gradescope_submit` command from previous projects* 16 | 17 | ## Link Github to Gradescope 18 | 19 | Log into your gradescope account and go to your account settings. Scroll down to the `Linked Accounts` section. If you do not already 20 | have your Github account linked here, click the `Link a GitHub account` button and log into your Github account. 21 | 22 | ## Using the new submit command 23 | 24 | First make sure all your changes are pushed to github using the `git add`, `git commit`, and `git push` commands. 25 | 26 | Next, to submit your project using the new submit command you can run `submit` from your project directory. 27 | 28 | The new `submit` comand will pull your code from GitHub, not your local files. If you do not push your changes to GitHub, 29 | they will not be uploaded to gradescope. 30 | -------------------------------------------------------------------------------- /projects/project3/SETS.md: -------------------------------------------------------------------------------- 1 | # Sets module 2 | 3 | ## `elem x a` 4 | 5 | - Type: `'a -> 'a list -> bool` 6 | - Description: Returns true iff `x` is an element of the set `a`. 7 | - Examples: 8 | ```ocaml 9 | elem 2 [] = false 10 | elem 3 (insert 5 (insert 3 (insert 2 []))) = true 11 | elem 4 (insert 3 (insert 2 (insert 5 []))) = false 12 | ``` 13 | 14 | ## `insert x a` 15 | 16 | - Type: `'a -> 'a list -> 'a list` 17 | - Description: Inserts `x` into the set `a`. 18 | - Examples: 19 | ```ocaml 20 | insert 2 [] = [2] 21 | insert 3 (insert 2 []) = [3; 2] 22 | insert 3 (insert 3 (insert 2 [])) = [3; 2] 23 | ``` 24 | 25 | ## `insert_all xs a` 26 | 27 | - Type: `'a list -> 'a list -> 'a list` 28 | - Description: Inserts each element from `xs` into the set `a`. 29 | - Examples: 30 | ```ocaml 31 | insert_all [2; 3; 3] [] = [2; 3] 32 | insert_all [1; 2; 3] [4; 5; 6] = [1; 2; 3; 4; 5; 6] 33 | ``` 34 | 35 | ## `subset a b` 36 | 37 | - Type: `'a list -> 'a list -> bool` 38 | - Description: Return true iff `a` **is a** subset of `b`. Formally, A ⊆ B ⇔ ∀x(xϵA ⇒ xϵB). 39 | - Examples: 40 | ```ocaml 41 | subset (insert 2 (insert 4 [])) [] = false 42 | subset (insert 5 (insert 3 [])) (insert 3 (insert 5 (insert 2 []))) = true 43 | subset (insert 5 (insert 3 (insert 2 []))) (insert 5 (insert 3 [])) = false 44 | ``` 45 | 46 | ## `eq a b` 47 | 48 | - Type: `'a list -> 'a list -> bool` 49 | - Description: Returns true iff `a` and `b` are equal as sets. Formally, A = B ⇔ ∀x(xϵA ⇔ xϵB). (Hint: The subset relation is anti-symmetric.) 50 | - Examples: 51 | ```ocaml 52 | eq [] (insert 2 []) = false 53 | eq (insert 2 (insert 3 [])) (insert 3 []) = false 54 | eq (insert 3 (insert 2 [])) (insert 2 (insert 3 [])) = true 55 | ``` 56 | 57 | ## `remove x a` 58 | 59 | - Type: `'a -> 'a list -> 'a list` 60 | - Description: Removes `x` from the set `a`. 61 | - Examples: 62 | ```ocaml 63 | elem 3 (remove 3 (insert 2 (insert 3 []))) = false 64 | eq (remove 3 (insert 5 (insert 3 []))) (insert 5 []) = true 65 | ``` 66 | 67 | ## `diff a b` 68 | 69 | - Type: `'a list -> 'a list -> 'a list` 70 | - Description: Subtracts the set `b` from the set `a`. 71 | - Examples: 72 | ```ocaml 73 | diff [1; 2; 3] [1; 2; 3] = [] 74 | diff [1; 2; 3] [1; 4; 5] = [2; 3] 75 | diff [1; 2; 3] [4; 5; 6] = [1; 2; 3] 76 | ``` 77 | 78 | ## `union a b` 79 | 80 | - Type: `'a list -> 'a list -> 'a list` 81 | - Description: Returns the union of the sets `a` and `b`. Formally, A ∪ B = {x | xϵA ∨ xϵB}. 82 | - Examples: 83 | ```ocaml 84 | eq (union [] (insert 2 (insert 3 []))) (insert 3 (insert 2 [])) = true 85 | eq (union (insert 5 (insert 2 [])) (insert 2 (insert 3 []))) (insert 3 (insert 2 (insert 5 []))) = true 86 | eq (union (insert 2 (insert 7 [])) (insert 5 [])) (insert 5 (insert 7 (insert 2 []))) = true 87 | ``` 88 | 89 | ## `intersection a b` 90 | 91 | - Type: `'a list -> 'a list -> 'a list` 92 | - Description: Returns the intersection of sets `a` and `b`. Formally, A ∩ B = {x | xϵA ∧ xϵB}. 93 | - Examples: 94 | ```ocaml 95 | eq (intersection (insert 3 (insert 5 (insert 2 []))) []) [] = true 96 | eq (intersection (insert 5 (insert 7 (insert 3 (insert 2 [])))) (insert 6 (insert 4 []))) [] = true 97 | eq (intersection (insert 5 (insert 2 [])) (insert 4 (insert 3 (insert 5 [])))) (insert 5 []) = true 98 | ``` 99 | 100 | ## `cat x a` 101 | 102 | - Type: `'a -> 'b list -> ('a * 'b) list` 103 | - Description: Turns each element of `a` into a 2-tuple where the first element is `x`. 104 | - Examples: 105 | ```ocaml 106 | cat 1 [2; 3; 4] = [(1,2); (1,3); (1,4)] 107 | cat 3 [] = [] 108 | cat "hi" [1; 2] = [("hi", 1); ("hi", 2)] 109 | ``` 110 | -------------------------------------------------------------------------------- /projects/project3/images/m_viz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/projects/project3/images/m_viz.png -------------------------------------------------------------------------------- /projects/project3/images/n_viz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/projects/project3/images/n_viz.png -------------------------------------------------------------------------------- /projects/project3/subset.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmsc330-umd/spring23/f9a505429c3eb74d39473ff6567755bfbbf322bf/projects/project3/subset.pdf -------------------------------------------------------------------------------- /projects/project4a/GRADESCOPE_SUBMIT.md: -------------------------------------------------------------------------------- 1 | # New Submission prosses 2 | 3 | *Note the new submission process is completely optional and the `gradescope_submit` command from previous projects will continue to work.* 4 | 5 | We are working on a new version of the `gradescope_submit` command and would appreciate student helping us 6 | to test the new process with project 2b. The new submission process is described below. 7 | 8 | ## Installing new command 9 | 10 | To install the new `submit` command complete the following steps: 11 | 12 | 1. Update your `opam` repository by running: `opam update` 13 | 2. Install the new version of submit by running: `opam install gradescope_submit` 14 | 15 | *Note: This will not conflict with the `gradescope_submit` command from previous projects* 16 | 17 | ## Link Github to Gradescope 18 | 19 | Log into your gradescope account and go to your account settings. Scroll down to the `Linked Accounts` section. If you do not already 20 | have your Github account linked here, click the `Link a GitHub account` button and log into your Github account. 21 | 22 | ## Using the new submit command 23 | 24 | First make sure all your changes are pushed to github using the `git add`, `git commit`, and `git push` commands. 25 | 26 | Next, to submit your project using the new submit command you can run `submit` from your project directory. 27 | 28 | The new `submit` comand will pull your code from GitHub, not your local files. If you do not push your changes to GitHub, 29 | they will not be uploaded to gradescope. 30 | -------------------------------------------------------------------------------- /projects/project4b/.submit: -------------------------------------------------------------------------------- 1 | [course] 2 | id = 489995 3 | name = "CMSC330" 4 | term = "Spring 2023" 5 | 6 | [assignment] 7 | id = 2800548 8 | name = "Project 4b" 9 | files = [ "src/eval.ml", "src/lexer.ml", "src/parser.ml" ] 10 | -------------------------------------------------------------------------------- /projects/project4b/GRADESCOPE_SUBMIT.md: -------------------------------------------------------------------------------- 1 | # New Submission prosses 2 | 3 | *Note the new submission process is completely optional and the `gradescope_submit` command from previous projects will continue to work.* 4 | 5 | We are working on a new version of the `gradescope_submit` command and would appreciate student helping us 6 | to test the new process with project 2b. The new submission process is described below. 7 | 8 | ## Installing new command 9 | 10 | To install the new `submit` command complete the following steps: 11 | 12 | 1. Update your `opam` repository by running: `opam update` 13 | 2. Install the new version of submit by running: `opam install gradescope_submit` 14 | 15 | *Note: This will not conflict with the `gradescope_submit` command from previous projects* 16 | 17 | ## Link Github to Gradescope 18 | 19 | Log into your gradescope account and go to your account settings. Scroll down to the `Linked Accounts` section. If you do not already 20 | have your Github account linked here, click the `Link a GitHub account` button and log into your Github account. 21 | 22 | ## Using the new submit command 23 | 24 | First make sure all your changes are pushed to github using the `git add`, `git commit`, and `git push` commands. 25 | 26 | Next, to submit your project using the new submit command you can run `submit` from your project directory. 27 | 28 | The new `submit` comand will pull your code from GitHub, not your local files. If you do not push your changes to GitHub, 29 | they will not be uploaded to gradescope. 30 | -------------------------------------------------------------------------------- /projects/project4b/README.md: -------------------------------------------------------------------------------- 1 | # Project 4B: MicroCaml Interpreter 2 | Due: ~~April 23th, 2023, 11:59PM (Late: April 24th, 2023, 11:59PM)~~ April 30th, 2023, 11:59PM (Late: May 1st, 2023, 11:59PM) 3 | 4 | Points: 48 public, 52 semipublic 5 | 6 | ## Introduction 7 | 8 | This is part (B) of project 4, in which you implement an interpreter for MicroCaml. 9 | 10 | In particular, you will implement two functions, `eval_expr` and `eval_mutop`. Each of these takes an `environment` (defined in [microCamlTypes.ml](./src/microCamlTypes.ml)) as a parameter, which acts as a map from variables to values. The `eval_expr` function evaluates an expression in the given environment, returning a `value`, while `eval_mutop` takes a `mutop` -- a top-level directive -- and returns a possibly updated environment and any additional result. 11 | 12 | You will need to use Imperative OCaml -- notably references -- to implement this project. This use is small, but important. More details below. 13 | 14 | ### Ground Rules and Extra Info 15 | 16 | The interpreter must be implemented in `eval.ml` in accordance with the signatures for `eval_expr` and `eval_mutop` found in [eval.mli](./src/eval.mli). `eval.ml` is the only file you will write code in. 17 | 18 | In your code, you may use any standard library functions, but the ones that will be useful to you will be found in the [`Stdlib` module][stdlib doc]. If you come asking for help using something we have not taught we will direct you to use methods taught in this class. 19 | 20 | ### Compilation, Tests, and Running 21 | 22 | You can submit by either running `gradescope-submit` or `submit` (if you have installed the new version of gradescope submit on your computer). 23 | Instructions to use the new optional submit process can be found [here](./GRADESCOPE_SUBMIT.md) 24 | 25 | You can also manually submit to [Gradescope](https://www.gradescope.com). *You may only submit the `eval.ml`, `lexer.ml`, `parser.ml` files.* 26 | 27 | You do not need a working parser and lexer to implement this project --- all testing can be done on abstract syntax trees directly. 28 | 29 | To test locally, run `dune runtest -f`. To test from the toplevel, run `dune utop src`. The necessary functions and types will automatically be imported for you. For example, from `utop`, you can write: 30 | 31 | ```ocaml 32 | eval_expr [] (Let ("x", false, Value (Bool true), ID "x"));; 33 | - : value = Bool true 34 | ``` 35 | 36 | ### Running Mutop 37 | 38 | If you do have a working parser and lexer, you can run them and your interpreter together in *mutop* (Micro-utop), a version of `utop` for MicroCaml. Run the command `dune exec bin/mutop.exe` in your terminal or use the shell script `bash mutop.sh` to start the mutop toplevel. The toplevel uses your implementations for `parse_mutop` and `eval_mutop` to execute MicroCaml expressions. Here is an example of its use: 39 | 40 | ![Mutop Example](assets/ex.gif) 41 | 42 | **Note:** If you are having issues running *mutop*, run the command `dune build` before starting the mutop toplevel. 43 | 44 | ## Operational Semantics 45 | 46 | We are going to describe how to implement your interpreter using examples, below. A more succinct description is this [operational semantics](./microcaml-opsem.pdf). Even if you don't use it much to do the project, we expect you to understand it -- we may take questions from it for the exam. 47 | 48 | ## Part 1: Evaluating Expressions 49 | ### `eval_expr : environment -> expr -> value` 50 | 51 | This function takes an environment `env` and an expression `e`, which is type `expr`, and produces the result of evaluating `e`, which is something of type `value`. All of the types mentioned here are defined in [microCamlTypes](src/microCamlTypes.ml); do not change any of them! 52 | 53 | The environment `env` is a `(var * value ref) list`, where `var` refers to an variable name (which is a string), and the `value ref` refers to its corresponding value in the `environment`; it's a `ref` because the value could change, due to implementing recursion, as discussed for `Let` below. Elements earlier in the list shadow elements later in the list. 54 | 55 | There are three possible error cases, represented by three different exceptions (in `eval.ml` -- do not change): 56 | 57 | ```ocaml 58 | exception TypeError of string 59 | exception DeclareError of string 60 | exception DivByZeroError 61 | ``` 62 | 63 | A `TypeError` happens when an operation receives an argument of the wrong type; a `DeclareError` happens when an ID is seen that has not been declared; and a `DivByZeroError` happens on attempted division by zero. We do not enforce what messages you use when raising the `TypeError` or `DeclareError` exceptions. That's up to you. 64 | 65 | Evaluation of subexpressions should be done from left to right to ensure that lines with multiple possible errors match up with our expected errors. 66 | 67 | Now we describe what your interpreter should do for each kind of `expr`, i.e., 68 | 69 | ```ocaml 70 | type expr = 71 | | Value of value 72 | | ID of var 73 | | Fun of var * expr 74 | | Not of expr 75 | | Binop of op * expr * expr 76 | | If of expr * expr * expr 77 | | FunctionCall of expr * expr 78 | | Let of var * bool * expr * expr 79 | ``` 80 | 81 | ### Value 82 | 83 | A `value` is defined as 84 | ```ocaml 85 | type value = 86 | | Int of int 87 | | Bool of bool 88 | | String of string 89 | | Closure of environment * var * expr 90 | ``` 91 | Values (often literals in the original source program) evaluate to themselves, i.e., 92 | 93 | ```ocaml 94 | eval_expr [] (Value(Int 1)) = Int 1 95 | eval_expr [] (Value(Bool false)) = Bool false 96 | eval_expr [] (Value(String "x")) = String "x" 97 | ``` 98 | 99 | A *closure* is the result of evaluating an anonymous function; it, too, evaluates to itself. We will discuss closures in detail when considering anonymous functions, and function calls, below. 100 | ```ocaml 101 | eval_expr [] (Value(Closure ([], "x", Fun ("y", Binop (Add, ID "x", ID "y"))))) = Closure ([], "x", Fun ("y", Binop (Add, ID "x", ID "y"))) 102 | ``` 103 | 104 | ### ID 105 | 106 | An identifier evaluates to whatever value it is mapped to by the environment. Should raise a `DeclareError` if the identifier has no binding. 107 | 108 | ```ocaml 109 | eval_expr [("x", ref (Int 1))] (ID "x") = Int 1 110 | eval_expr [] (ID "x") (* DeclareError "Unbound variable x" *) 111 | ``` 112 | 113 | See the discussion of `Let` below for advice about managing environments. 114 | 115 | ### Not 116 | 117 | The unary `not` operator operates only on booleans and produces a `Bool` containing the negated value of the contained expression. If the expression in the `Not` is not a boolean (or does not evaluate to a boolean), a `TypeError` should be raised. 118 | 119 | ```ocaml 120 | eval_expr [("x", ref (Bool true))] (Not (ID "x")) = Bool false 121 | eval_expr [("x", ref (Bool true))] (Not (Not (ID "x"))) = Bool true 122 | eval_expr [] (Not (Value(Int 1))) (* TypeError "Expected type bool" *) 123 | ``` 124 | 125 | ### Binop 126 | 127 | There are five sorts of binary operator: Those carrying out integer arithmetic; those carrying out integer ordering comparisons; one carrying out string concatenation; and one carrying out equality (and inequality) comparisons; and those implementing boolean logic. 128 | 129 | #### Add, Sub, Mult, and Div 130 | 131 | Arithmetic operators work on integers; if either argument evaluates to a non-`Int`, a `TypeError` should be raised. An attempt to divide by zero should raise a `DivByZeroError` exceptio. 132 | 133 | ```ocaml 134 | eval_expr [] (Binop (Add, Value(Int 1), Value(Int 2))) = Int 3 135 | eval_expr [] (Binop (Add, Value(Int 1), Value(Bool false))) (* TypeError "Expected type int" *) 136 | eval_expr [] (Binop (Div, Value(Int 1), Value(Int 0))) (* DivByZeroError *) 137 | ``` 138 | 139 | #### Greater, Less, GreaterEqual, and LessEqual 140 | 141 | These relational operators operate only on integers and produce a `Bool` containing the result of the operation. If either argument evaluates to a non-`Int`, a `TypeError` should be raised. 142 | 143 | ```ocaml 144 | eval_expr [] (Binop(Greater, Value(Int 1), Value(Int 2))) = Bool false 145 | eval_expr [] (Binop(LessEqual, Value(Bool false), Value(Bool true))) (* TypeError "Expected type int" *) 146 | ``` 147 | 148 | #### Concat 149 | 150 | This operation returns the result of concatenating two strings; if either argument evaluates to a non-`String`, a `TypeError` should be raised. 151 | 152 | ```ocaml 153 | eval_expr [] (Binop (Concat, Value(Int 1), Value(Int 2))) (* TypeError "Expected type string" *) 154 | eval_expr [] (Binop (Concat, Value(String "hello "), Value(String "ocaml"))) = String "hello ocaml" 155 | ``` 156 | 157 | #### Equal and NotEqual 158 | 159 | The equality operators require both arguments to be of the same type. The operators produce a `Bool` containing the result of the operation. If the two arguments to these operators do not evaluate to the same type (e.g., one boolean and one integer), a `TypeError` should be raised. Moreover, we *cannot compare two closures for equality* -- to do so risks an infinite loop because of the way recursive functions are implemented; trying to compare them also raises `TypeError` (OCaml does the same thing in its implementation, BTW). 160 | 161 | ```ocaml 162 | eval_expr [] (Binop(NotEqual, Value(Int 1), Value(Int 2))) = Bool true 163 | eval_expr [] (Binop(Equal, Value(Bool false), Value(Bool true))) = Bool false 164 | eval_expr [] (Binop(Equal, Value(String "hi"), Value(String "hi"))) = Bool true 165 | eval_expr [] (Binop(NotEqual, Value(Int 1), Value(Bool false))) (* TypeError "Cannot compare types" *) 166 | ``` 167 | 168 | #### Or and And 169 | 170 | These logical operations operate only on booleans and produce a `Bool` result. If either argument evaluates to a non-`Bool`, a `TypeError` should be raised. 171 | 172 | ```ocaml 173 | eval_expr [] (Binop(Or, Value(Int 1), Value(Int 2))) (* TypeError "Expected type bool" *) 174 | eval_expr [] (Binop(Or, Value(Bool false), Value(Bool true))) = Bool true 175 | ``` 176 | 177 | ### If 178 | 179 | The `If` expression consists of three subexpressions - a guard, the true branch, and the false branch. The guard expression must evaluate to a `Bool` - if it does not, a `TypeError` should be raised. If it evaluates to `Bool true`, the true branch should be evaluated; else the false branch should be. 180 | 181 | ```ocaml 182 | eval_expr [] (If (Binop (Equal, Value (Int 3), Value (Int 3)), Value (Bool true), Value (Bool false))) = Bool true 183 | eval_expr [] (If (Binop (Equal, Value (Int 3), Value (Int 2)), Value (Int 5), Value (Bool false))) = Bool false 184 | ``` 185 | 186 | Notes: 187 | - Only one branch should be evaluated, not both. 188 | - The true and false branches **could evaluate to values having different types**. This is an effect of MicroCaml being dynamically typed. 189 | 190 | ### Let 191 | 192 | The `Let` consists of four components - an ID's name `var` (which is a string); a boolean indicating whether or not the bound variable is referenced in its own definition (i.e., whether it's *recursive*); the *initialization expression*; and the *body expression*. 193 | 194 | #### Non-recursive bindings 195 | 196 | For a non-recursive `Let`, we first evaluate the initialization expression, which produces a value *v* or raises an error. If the former, we then return the result of evaluating the body expression in an environment extended with a mapping from the `Let`'s ID variable to *v*. (Evaluating the body might cause an exception to be raised.) 197 | 198 | ```ocaml 199 | eval_expr [] (Let ("x", false, 200 | Binop (Add, Binop (Mult, Value (Int 2), 201 | Binop (Div, Value (Int 3), Value (Int 5))), Value (Int 4)), 202 | Binop (Sub, ID "x", Value (Int 5)))) = Int (-1) 203 | ``` 204 | 205 | #### Recursive bindings 206 | 207 | For a recursive `Let`, we evaluate the initialization expression in an environment extended with a mapping from the ID we are binding to a temporary placeholder; this way, the initialization expression is permitted to refer to itself, the ID being bound. Then, we *update* that placeholder to *v*, the result, before evaluating the body. 208 | 209 | The AST given in this example corresponds to the MicroCaml program `let rec f = fun x -> if x = 0 then x else (x + (f (x-1))) in f 8`: 210 | 211 | ```ocaml 212 | eval_expr [] (Let ("f", true, 213 | Fun ("x", 214 | If (Binop (Equal, ID "x", Value (Int 0)), ID "x", 215 | Binop (Add, ID "x", 216 | FunctionCall (ID "f", Binop (Sub, ID "x", Value (Int 1)))))), 217 | FunctionCall (ID "f", Value (Int 8)))) = Int 36 218 | ``` 219 | 220 | #### Environments 221 | 222 | Being able to modify the placeholder is made possibly by using references; this is why the type `environment` given in `microCamlTypes.ml` is `(var * value ref) list` and not `(var * value) list`. To make it easy to work with this kind of environment, we recommend you use the functions given at the top of `eval.ml`: 223 | 224 | - `extend env x v` produces an environment that extends `env` with a mapping from `x` to `v` 225 | - `lookup env x` returns `v` if `x` maps to `v` in `env`; if there are multiple mappings, it chooses the most recent. 226 | - `ref_extend_tmp x` produces an environment that extends `env` with a mapping from `x` to a temporary placeholder. 227 | - `ref_update env x v` produces an environment that updates `env` in place, modifying its most recent mapping for `x` to be `v` instead (removing the placeholder). 228 | 229 | However since references were not covered, we also gave you a variation of these functions that do not use references. If you choose to not use references you will need the `value` type given in the `eval.ml` file as well as the `remove` function that removes a variable,binding pair from an environment. 230 | 231 | Regardless if you use references or not, you do not have to use these functions for the project or they can be modified to fit your needs. THey are mostly here to guide you on a correct track. 232 | 233 | ### Fun 234 | 235 | The `Fun` is used for anonymous functions, which consist of two components - a parameter, which is a string as an ID's name, and a body, which is an expression. A `Fun` evaluates to a `Closure` that captures the current environment, so as to implement lexical (aka static) scoping. 236 | 237 | ```ocaml 238 | eval_expr [("x", ref (Bool true))] (Fun ("y", Binop (And, ID "x", ID "y"))) 239 | = Closure ([("x", ref (Bool true))], "y", Binop (And, ID "x", ID "y")) 240 | eval_expr [] (Fun ("x", Fun ("y", Binop (And, ID "x", ID "y")))) 241 | = Closure ([], "x", Fun ("y", Binop (And, ID "x", ID "y"))) 242 | ``` 243 | 244 | ### FunctionCall 245 | 246 | The `FunctionCall` has two subexpressions. We evaluate the first subexpression to a `Closure(A,x,e)` (otherwise, a `TypeError` should be raised) and the second subexpression to a value *v*. Then we evaluate `e` (the closure's body) in environment `A` (the closure's environment), returning the result. 247 | 248 | ```ocaml 249 | eval_expr [] (FunctionCall (Value (Int 1), Value (Int 1))) (* TypeError "Not a function" *) 250 | eval_expr [] (Let ("f", false, Fun ("x", Fun ("y", Binop (Add, ID "x", ID "y"))), 251 | FunctionCall (FunctionCall (ID "f", Value (Int 1)), Value (Int 2)))) = Int 3 252 | ``` 253 | 254 | The AST in the second example is equivalent to the MicroCaml expression `let f = fun x -> fun y -> x + y in (f 1) 2`. 255 | 256 | ## Part 2: Evaluating Mutop Directive 257 | ### `eval_mutop : environment -> mutop -> environment * (value option)` 258 | 259 | This function evaluates the given `mutop` directive in the given `environment`, returning an updated environment with an optional `value` as the result. There are three kinds of `mutop` directive (as defined in [microCamlTypes.ml](./src/microCamlTypes.ml)): 260 | 261 | ```ocaml 262 | type mutop = 263 | | Def of var * expr 264 | | Expr of expr 265 | | NoOp 266 | ``` 267 | 268 | ### Def 269 | 270 | For a `Def`, we evaluate its `expr` in the given environment, but with a placeholder set for `var` (see the discussion of recursive `Let`, above, for more about environment placeholders), producing value *v*. We then update the binding for `var` to be *v* and return the extended environment, along with the value itself. 271 | 272 | ```ocaml 273 | eval_mutop [] (Def ("x", Value(Bool(true)))) = ([("x", {contents = Bool true})], Some (Bool true)) 274 | ``` 275 | ```ocaml 276 | eval_mutop [] Def ("f", 277 | Fun ("y", 278 | If (Binop (Equal, ID "y", Value (Int 0)), Value (Int 1), 279 | FunctionCall (ID "f", Binop (Sub, ID "y", Value (Int 1)))))) = 280 | ([("f", 281 | {contents = 282 | Closure (, "y", 283 | If (Binop (Equal, ID "y", Value (Int 0)), Value (Int 1), 284 | FunctionCall (ID "f", Binop (Sub, ID "y", Value (Int 1)))))})], 285 | Some 286 | (Closure ([("f", {contents = })], "y", 287 | If (Binop (Equal, ID "y", Value (Int 0)), Value (Int 1), 288 | FunctionCall (ID "f", Binop (Sub, ID "y", Value (Int 1))))))) 289 | ``` 290 | 291 | ### Expr 292 | For a `Expr`, we should evaluate the expression in the given environment, and return that environment and the resulting value. 293 | 294 | ```ocaml 295 | eval_mutop [] (Expr (FunctionCall (Fun ("x", 296 | Binop (Concat, Value (String "("), 297 | Binop (Concat, ID "x", Value (String ")")))), 298 | Value (String "parenthesis")))) = ([], Some (String "(parenthesis)")) 299 | ``` 300 | 301 | ### NoOp 302 | 303 | The `NoOp` should return the original environment and no value (`None`). 304 | 305 | ```ocaml 306 | eval_mutop [] NoOp = ([], None) 307 | ``` 308 | 309 | ## Academic Integrity 310 | 311 | Please **carefully read** the academic honesty section of the course syllabus. Most commonly this includes posting this project and its solution online to a public repo. **Any evidence** of impermissible cooperation on projects, use of disallowed materials or resources, or unauthorized use of computer accounts, **will be** submitted to the Student Honor Council, which could result in an XF for the course, or suspension or expulsion from the University. Be sure you understand what you are and what you are not permitted to do in regards to academic integrity when it comes to project assignments. These policies apply to all students, and the Student Honor Council does not consider lack of knowledge of the policies to be a defense for violating them. Full information is found in the course syllabus, which you should review before starting. 312 | 313 | 314 | 315 | 316 | [stdlib doc]: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Stdlib.html 317 | -------------------------------------------------------------------------------- /projects/project5/.submit: -------------------------------------------------------------------------------- 1 | [course] 2 | id = 489995 3 | name = "CMSC330" 4 | term = "Spring 2023" 5 | 6 | [assignment] 7 | id = 2855552 8 | name = "Project 5" 9 | files = [ "src/basics.rs", "src/locator.rs" ] 10 | -------------------------------------------------------------------------------- /projects/project5/README.md: -------------------------------------------------------------------------------- 1 | # Project 5: Stark Suit Repair 2 | Due: May 11, 2023 at 11:59pm (Late Deadline: May 12th, 2023, 11:59PM) 3 | 4 | Public: 48pts, Semipublic: 52pts 5 | 6 | Ground Rules 7 | --------------------------- 8 | **This is an individual assignment. You must work on this project alone.** 9 | 10 | For this project you are allowed to use the library functions found in `std`, including `Vec`, `String`, `collections::HashMap`, and `Box`. 11 | 12 | However, you may **NOT** use `collections::BinaryHeap` for your implementation. You must create your own. 13 | 14 | Also, you may not use any external crates for your implementation. 15 | 16 | Introduction 17 | ------------ 18 | Tony Stark, a genius and master engineer who received his education at MIT, is best known under the alias Iron Man. Stark built the Iron Man suit for his protection and went on to run his father's company, where he continues to improve his super suit. 19 | 20 | You have been hired to work for Stark Industries! 21 | 22 | Recently, Stark has been feeling skeptical of his suit's software. Fearing for his safety, he decides to rewrite his code from C to Rust. Rust is a type-safe language with no garbage collector where the developer does not have to worry about managing memory. The proper amount of memory is promised to be allocated for you and objects are also deallocated for you too. Typically unmanaged code has performance gains but is vulnerable to security risks such as buffer overflows where attackers can steal data or modify memory, as would happen in C if the code isn't managed properly. However, in Rust, we can write fast/efficient unmanaged code AND be memory safe! 23 | 24 | This is where you come in. Stark is unfamiliar with the language and needs you to help him fix his suit as well as add some additional features. 25 | 26 | Project Files 27 | ------------- 28 | * Rust Files 29 | * __src/lib.rs__: This file describes the structure of the Rust library you are making. You should not modify it. 30 | * __src/basics.rs__: This file contains the functions you must implement for part 1. 31 | * __src/locator.rs__: This file contains the functions you must implement for parts 2 and 3. 32 | * __tests/public/mod.rs__: These are the public tests. Feel free to write your own. 33 | 34 | Compilation and Tests 35 | --------------------- 36 | In order to compile the project, simply run `cargo build`. To test, run `cargo test` in the root directory of the project. The tests won't run if any part of the project does not compile. 37 | 38 | Installing Rust and Cargo 39 | ------------------------- 40 | If you are working in grace, run `module avail rust` every time you log in. 41 | 42 | For instructions on installing Rust, please see the [Install Rust](https://www.rust-lang.org/tools/install) page. 43 | 44 | Part 1: Basic Warmups 45 | --------------------- 46 | As mentioned earlier, Stark does not know the syntax of the rust language very well. He attempted to write a few simple functions but failed to do so. 47 | 48 | In this part of the project, you will be tasked with implementing the simple functions that Stark had trouble with. 49 | 50 | `fn gauss(n: i32) -> i32` 51 | * **Description**: Returns the sum 1 + 2 + ... + n. If n is negative, return -1. 52 | * **Examples**: 53 | ``` 54 | gauss(3) => 6 55 | gauss(10) => 55 56 | gauss(-17) => -1 57 | ``` 58 | 59 | `fn in_range(lst: &[i32], s: i32, e: i32) -> i32` 60 | * **Description**: Returns the number of elements in the list that are in the range [s,e]. 61 | * **Examples**: 62 | ``` 63 | in_range(&[1,2,3], 2, 4) => 2 64 | in_range(&[1,2,3], 4, 7) => 0 65 | ``` 66 | 67 | `fn subset(set: &[T], target: &[T]) -> bool` 68 | * **Description**: Returns true if target is a subset of set, false otherwise. 69 | * **Examples**: 70 | ``` 71 | subset(&[1,2,3,4,5], &[1,5,2]) => true 72 | subset(&[1,2,3,4,5], &[1,2,7]) => false 73 | subset(&['a','b','c'], &[]) => true 74 | ``` 75 | 76 | `fn mean(lst: &[f64]) -> Option` 77 | * **Description**: Returns the mean of elements in lst. If the list is empty, return None. 78 | * **Examples**: 79 | ``` 80 | mean(&[2.0, 4.0, 9.0]) => Some(5.0) 81 | mean(&[]) => None 82 | ``` 83 | 84 | `fn to_decimal(lst: &[i32]) -> i32` 85 | * **Description**: Converts a binary number to decimal, where each bit is stored in order in the array. 86 | * **Examples**: 87 | ``` 88 | to_decimal(&[1,0,0]) => 4 89 | to_decimal(&[1,1,1,1]) => 15 90 | ``` 91 | 92 | `fn factorize(n: u32) -> Vec` 93 | * **Description**: Decomposes an integer into its prime factors and returns them in a vector. You can assume factorize will never be passed anything less than 2. 94 | * **Examples**: 95 | ``` 96 | factorize(5) => [5] 97 | factorize(12) => [2,2,3] 98 | ``` 99 | 100 | `fn rotate(lst: &[i32]) -> Vec` 101 | * **Description**: Takes all of the elements of the given slice and creates a new vector. The new vector takes all the elements of the original and rotates them, so the first becomes the last, the second becomes first, and so on. 102 | * **Examples**: 103 | ``` 104 | rotate(&[1,2,3,4]) => [2,3,4,1] 105 | rotate(&[6,7,8,5]) => [7,8,5,6] 106 | ``` 107 | 108 | `fn substr(s: &String, target: &str) -> bool` 109 | * **Description**: Returns true if target is a subtring of s, false otherwise. You should not use the contains function of the string library in your implementation. 110 | * **Examples**: 111 | ``` 112 | substr(&"rustacean".to_string(), &"ace") => true 113 | substr(&"rustacean".to_string(), &"rcn") => false 114 | substr(&"rustacean".to_string(), &"") => true 115 | ``` 116 | 117 | `fn longest_sequence(s: &str) -> Option<&str>` 118 | * **Description**: Takes a string and returns the first longest substring of consecutive equal characters. 119 | * **Examples**: 120 | ``` 121 | longest_sequence(&"ababbba") => Some("bbb") 122 | longest_sequence(&"aaabbb") => Some("aaa") 123 | longest_sequence(&"xyz") => Some("x") 124 | longest_sequence(&"") => None 125 | ``` 126 | 127 | Part 2: Min Heap Priority Queue 128 | ------------------------------- 129 | In this part, you will be responsible for creating a min heap. This data structure will be helpful in making part 3 easier (although not necessary for completion). 130 | 131 | Before implementing the following methods, it may be helpful to review how heaps work. A min heap is a tree like structure where each node is smaller in value than it's children. Instead of implementing the structure with a tree, we will use an array based implementation for efficiency. 132 | 133 | If we index each node of a tree in level-order (starting at 0) we can calculate the parent index, left child index, and right child index as (idx-1 / 2), (2 * idx + 1), and (2 * idx + 2) respectively. 134 | 135 | All the functions in this part belong to the `PriorityQueue` trait. Traits are a neat feature in Rust (similar to Java interfaces) that allow us to add functionality to existing types. In this project, we implement the `PriorityQueue` trait for the `Vec` type, allowing us to use three new functions in all vector types. 136 | 137 | * `fn enqueue(&mut self, ele: T) -> ()` 138 | 139 | The first function you will write is the **enqueue** method. This method inserts an element into the heap. For insertion, the first step is to find the first available spot in the array, placing the new element at the end of the array. Then you must re-shape the structure so that it maintains the heap property of all children being larger than the parent. Keep swapping the newly added element with its parent until the constraint is satisfied. There is no return value for this method. 140 | 141 | * `fn dequeue(&mut self) -> Option` 142 | 143 | The second function you will write is the **dequeue** method. This method removes and returns the root element (or first element of array) from the heap. Once we remove the root element, we must replace it with the last element in the array and again re-shape the structure so that it maintains the heap property of all children being larger than the parent. Keep swapping the parent element with its smallest child until the constraint is satisfied. The return element should be returned in the form of an option. Return `Some(T)` if the heap is not empty. Otherwise return `None` if the heap is empty. 144 | 145 | * `fn peek(&self) -> Option<&T>` 146 | 147 | The last function you will write is the **peek** method. This method should return the element at the root of the heap without removing it in the form of an option. Return `Some(T)` if the heap is not empty. Otherwise return `None` if the heap is empty. 148 | 149 | Part 3: Target Locator 150 | ---------------------- 151 | When in a large battle with the rest of The Avengers, it can be unclear what is the best strategy to help the team fight crime. Stark wants to add a new feature to his suit that allows him to quickly determine which enemy he should fight whenever he is in large battles. 152 | 153 | * `fn distance(p1: (i32,i32), p2: (i32,i32)) -> i32` 154 | 155 | First, you will write a method called **distance**, that computes the orthogonal distance between two coordinates represented as tuples. 156 | 157 | Orthogonal distance is not direct like Euclidean distance. Instead, think about what is the least number of steps you need to move horizontally and vertically to get from one point to another. 158 | 159 | For instance, the orthogonal distance between (2, 3) and (5, 1) is 5 (3 steps to the right and 2 steps down). 160 | 161 | * `fn target_locator<'a>(allies: &'a HashMap<&String, (i32,i32)>, enemies: &'a HashMap<&String, (i32,i32)>) -> (&'a str,i32,i32)` 162 | 163 | Next, you will write a method called **target_locator**, that will return the name and coordinates of the enemy that Stark will fight. 164 | 165 | You are given the location of Stark, the location of your allies, and the location of the enemies in hashmaps, mapping names to coordinates. The number of enemies will always equal the number of allies (including Stark) so every enemy matches up with exactly one ally and no one is left out. 166 | 167 | Every ally will prioritize the closest enemy to them. But if another ally is closer and will beat them to the enemy, they will have to find the next closest enemy to battle. 168 | 169 | You should use the distance method to determine how close each ally is to each enemy. 170 | 171 | You may find it very helpful to use the priority queue from part 2 in pair with the provided Node struct to assist you in your implementation. 172 | 173 | To avoid ambiguity, assume no two pairs of allies and enemies have the same distance. 174 | An example battle is shown below. 175 | ``` 176 | ___________________ 177 | | A1 | | | | 178 | |____|____|____|____| 179 | | | | E1 | | 180 | |____|____|____|____| 181 | | | A2 | | | 182 | |____|____|____|____| 183 | | | | | E2 | 184 | |____|____|____|____| 185 | ``` 186 | 187 | A1 and A2 represent the two allies (including Stark) and E1 and E2 represent the two enemies. In this scenario, A2 will battle E1 while A1 would battle E2 despite being closer to E1. 188 | 189 | Resources 190 | --------- 191 | Below we've listed some helpful links to functions you may want to consider using for your project. The Rust-lang online textbook is a terrific resource. You can find just about anything you need for this project in the book. 192 | 193 | * [integers][integers] 194 | * [vectors][vectors] 195 | * [strings][strings] 196 | * [str][str] 197 | * [iterators][iterators]: some notable functions being collect, enumerate, zip 198 | * [options][options] 199 | 200 | Project Submission 201 | ------------------ 202 | 203 | The easiest way to submit is to navigate to the project directory and run `gradescope-submit` in the root of the project 5 repository. 204 | 205 | If you submit another way, you must submit the files `basics.rs`, and `locator.rs` containing your solution. You may submit other files, but they will be ignored during grading. We will run your solution as individual tests just as in the provided public test file. **No tests will pass on the submit server if the project does not compile!** 206 | 207 | Be sure to follow the project description exactly! Your solution will be graded automatically, so any deviation from the specification will result in lost points. 208 | 209 | Academic Integrity 210 | ------------------ 211 | Please **carefully read** the academic honesty section of the course syllabus. **Any evidence** of impermissible cooperation on projects, use of disallowed materials or resources, or unauthorized use of computer accounts, **will** be submitted to the Student Honor Council, which could result in an XF for the course, or suspension or expulsion from the University. Be sure you understand what you are and what you are not permitted to do in regards to academic integrity when it comes to project assignments. These policies apply to all students, and the Student Honor Council does not consider lack of knowledge of the policies to be a defense for violating them. Full information is found in the course syllabus, which you should review before starting. 212 | 213 | [integers]: https://doc.rust-lang.org/std/primitive.i32.html 214 | [vectors]: https://doc.rust-lang.org/std/vec/struct.Vec.html 215 | [strings]: https://doc.rust-lang.org/std/string/struct.String.html 216 | [str]: https://doc.rust-lang.org/std/primitive.str.html 217 | [iterators]: https://doc.rust-lang.org/std/iter/trait.Iterator.html 218 | [options]: https://doc.rust-lang.org/std/option/enum.Option.html 219 | --------------------------------------------------------------------------------