├── .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 | 
72 |
73 | 
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 |
12 |
13 | ### Problem 2:
14 |
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 |
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 | 
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 |
--------------------------------------------------------------------------------