- 02-15 - updated description for
is_prime
to specify that negative numbers are not prime.
CMSC 330, Spring 2021
Due February 22 (first late February 23, 10% penalty; second late March 1, 75% penalty).
Points: 65 public, 20 semipublic, 15 secret
This is an individual assignment. You must work on this project alone.
The goal of this project is to get you familiar with programming in OCaml. You will have to write a number of small functions, each of which is specified in three sections below.
We recommend you get started right away, going from top to bottom. The problems get increasingly more challenging, and in some cases later problems can take advantage of earlier solutions.
In your code, you may only use library functions found in the Stdlib
module. (This means you may not use the List
module!) You may not use any imperative structures of OCaml such as references.
You will submit this project to Gradescope. You may only submit the basics.ml file.
To test locally, run dune runtest -f
from the setup
directory. We recommend you write student tests in test/student/student.ml
.
You can interactively test your code by doing dune utop src
(assuming you have utop
). Then you should be able to use any of the functions. All of your commands in utop
need to end with two semicolons (i.e. ;;
), otherwise it will appear that your terminal is hanging.
Besides the provided public tests, you will also find the file student.ml on test/student/
, where you'll be able to add OUnit tests of your own. More detailed information about writing tests can be found here. Here are the timestamps for the topics covered in the video:
- Installing necessary software: 00:46
- How to build and test: 01:14
- List all available tests: 04:40
- Running a specific test: 05:05
- Testing inside of utop: 09:00
- Understanding test cases: 16:00
- Writing your own test cases: 19:20
This project also includes Property-based tests (PBT) for you to use. Property based testing enables pretty good test coverage without having to write a lot of individual tests. In particular, you specify a property that your code should have on many possible inputs, not just a particular one, and the property tester will generate lots of random inputs against which to test the property.
The property-based tests (PBTs) we've provided are not meant to test your code entirely, but rather to give you a little help. You should still write your own tests. You can write typical unit tests (and/or test using utop
or the ocaml
top level), or if you like you can write more PBTs. You can find the provided PBTs in test/property-based-test
, along with comments and instructions on how to expand them. We'll cover PBTs in more detail later in the class, so don't feel obligated to play with these now.
The following are the relevant files for your code:
- OCaml Files
- src/basics.ml: You will write your code here, in this file.
- src/basics.mli: This file is used to describe the signature of all the functions in the module. Do not modify this file; Gradescope will use the original version.
OCaml is a lot different than languages you're likely used to working with, and we'd like to point out a few quirks here that may help you work your way out of common issues with the language.
- Unlike most other languages, = in OCaml is the operator for structural equality whereas == is the operator for physical equality. All functions in this project (and in this course, unless ever specified otherwise) are concerned with structural equality.
- The binary subtraction operator (
-
) also doubles as the unary minus operator forint
s andfloat
s in OCaml. As a result, the parser has trouble identifying the difference between subtraction and a negative number. When writing negative numbers, it's safest to surround them in parentheses; e.g.,some_function 5 (-10)
works, wheresome_function 5 -10
will give an error. - Recursive functions in OCaml require the use of the
rec
keyword. We don't include therec
keyword for certain functions inbasics.ml
to show that the function can be written without recursion. Addingrec
to a non-recursive function usually has no effect (unless there is some sort of shadowing going on).
- Some parts of this project are additive, meaning your solutions to earlier functions can be used to aid in writing later functions. Think about this in part 3.
- You can always add a helper function for any of the functions we ask you to implement, and the helper function can also be recursive.
- You may move around the function definitions. In OCaml, in order to use one function inside of another, you need to define the function before it is called. For example, if you think that a function from Part 2 can be used to help you implement a function in Part 1, you can move your implementation of the function from the Part 2 section to before the function in Part 1. As long as you still pass the tests and you haven't created a syntax error, you are fine.
- Pay special notice to a function's type. Often times, you can lose sight of what you're trying to do if you don't remind yourself of the types of the arguments and the type of what you're trying to return.
- You may rename arguments however you would like, but do not modify function's name. Doing so will cause you to fail the function's tests.
Implement the following functions that do not require recursion. Accordingly, these functions are defined without the rec
keyword, but you MAY add the rec
keyword to any of the following functions or write a recursive helper function. Just remember that if you write a helper function, it must be defined in the file before it is called.
- Type:
'a * 'b * 'c -> 'c * 'b * 'a
- Description: Returns a 3-tuple in the reverse order of
tup
. - Examples:
rev_tup (1, 2, 3) = (3, 2, 1) rev_tup (1, 1, 1) = (1, 1, 1) rev_tup ("a", 1, "c") = ("c", 1, "a")
- Type:
int -> int
- Description: Returns the absolute value of
x
. - Examples:
abs 1 = 1 abs (-5) = 5
- Type:
int * int -> int * int -> int
- 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.
- Examples:
area (1, 1) (2, 2) = 1 area (2, 2) (1, 1) = 1 area (2, 1) (1, 2) = 1 area (0, 1) (2, 3) = 4 area (1, 1) (1, 1) = 0 area ((-1), (-1)) (1, 1) = 4
- Type:
int * int * int -> int * int * int -> int
- Description: Takes in the Cartesian coordinates (3-dimensional) of two opposite corners of a rectangular prism and returns its volume. The sides of the rectangular prism are parallel to the axes.
- Examples:
volume (1, 1, 1) (2, 2, 2) = 1 volume (2, 2, 2) (1, 1, 1) = 1 volume (0, 1, 2) (2, 3, 5) = 12 volume (1, 1, 1) (1, 1, 1) = 0 volume ((-1), (-1), (-1)) (1, 1, 1) = 8
Implement the following functions using recursion.
- Type:
int -> int
- Description: Returns the
n
th term of the fibonacci sequence. - Assumptions:
n
is non-negative, and we will not test your code for integer overflow cases. - Examples:
fibonacci 0 = 0 fibonacci 1 = 1 fibonacci 3 = 2 fibonacci 6 = 8
- Type:
int -> int -> int
- Description: Returns
x
raised to the powerp
. - Assumptions:
p
is non-negative, and we will not test your code for integer overflow cases. - Examples:
pow 3 1 = 3 pow 3 2 = 9 pow (-3) 3 = -27
- Type:
int -> int -> int
- Description: Returns the log of
y
with basex
rounded-down to an integer. - Assumptions: You may assume the answer is non-negative,
x
>= 2, andy
>= 1. - Examples:
log 4 4 = 1 log 4 16 = 2 log 4 15 = 1 log 4 64 = 3
- Type:
int -> bool
- Description: Returns whether or not
x
is prime. Note that all negative numbers are non-prime. - Examples:
is_prime 1 = false is_prime 2 = true is_prime 3 = true is_prime 4 = false is_prime 5 = true is_prime 60 = false is_prime 61 = true is_prime -2 = false
- Type:
int -> int
- Description: Returns the smallest prime number greater than or equal to
x
. - Examples:
next_prime 1 = 2 next_prime 2 = 2 next_prime 3 = 3 next_prime 4 = 5 next_prime 60 = 61 next_prime -20 = 2
- Type:
int -> 'a list -> 'a
- Description: Returns the element at the index
idx
in the listlst
. Ifidx
is past the bounds oflst
, raise an error usingfailwith "Out of bounds"
. - Assumptions:
idx
is non-negative. - Examples:
get 0 [26; 11; 99] = 26 get 1 [26; 11; 99] = 11 get 2 [26; 11; 99] = 99 get 3 [26; 11; 99] = Exception get 0 ["a"; "b"] = "a" get 1 ["a"; "b"] = "b" get 2 ["a"; "b"] = Exception
- Type:
'a list -> 'a list -> 'a list
- Description: Returns the longer list provided as an argument, returns the empty list if the two lists are the same length.
- Examples:
larger [] [] = [] larger [1] [2; 3] = [2; 3] larger [2; 4] [2] = [2; 4] larger [4; 1; 2] [3; 5; 7] = []
- Type:
'a list -> 'a list
- Description: Returns a list with the elements of
lst
but in reverse order. - Examples:
reverse [] = [] reverse [1] = [1] reverse [1; 2; 3] = [3; 2; 1] reverse ["a"; "b"; "c"] = ["c"; "b"; "a"]
- Type:
'a list -> 'a list -> 'a list
- Description: Returns a list with the elements of
lst1
followed by the elements oflst2
. The elements within each list must be in the same order. You may not use the@
operator to write this function (that is, in this function or any helper functions). - Examples:
combine [] [] = [] combine [] [3; 4] = [3; 4] combine [1; 2; 3; 4] [3; 4; 5] = [1; 2; 3; 4; 3; 4; 5] combine ["a"] ["b"] = ["a"; "b"]
- Type:
int -> 'a list -> 'a list
- Description: Move every element over in
lst
to the left by the givenshift
(looping around). - Assumptions:
shift
is non-negative. - Important Note: None of the public or semipublic tests check whether this function works. Write your own tests to verify that your behavior is what you would expect!
- Examples:
rotate 0 ["a"; "b"; "c"; "d"] = ["a"; "b"; "c"; "d"] rotate 1 ["a"; "b"; "c"; "d"] = ["b"; "c"; "d"; "a"] rotate 2 ["a"; "b"; "c"; "d"] = ["c"; "d"; "a"; "b"] rotate 3 ["a"; "b"; "c"; "d"] = ["d"; "a"; "b"; "c"] rotate 4 ["a"; "b"; "c"; "d"] = ["a"; "b"; "c"; "d"] rotate 5 ["a"; "b"; "c"; "d"] = ["b"; "c"; "d"; "a"]
- Type:
'a list -> bool
- Description: Returns true if
lst
is a palindrome and returns false otherwise. A palindrome is the same read forward and backward. - Important Note: Use wildcards
_
to make sure all match cases are exhaustive. - Examples:
is_palindrome [] = true is_palindrome [1; 2; 3; 2; 1] = true is_palindrome ["A"; "b"; "b"; "A"] = true is_palindrome ["O", "C", "A", "M"; "L"] = false
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.