MCS-287 Lab 1 (Spring 2024)

Due Thursday, March 7th, 2024, via Moodle, by the start of the class

What you are to turn in

This lab assignment calls on you to write a number of different function definitions. Collect and submit (via Moodle) your answers for all questions in a single file called hw1.sml. You are allowed to use the standard functions abs and length. You should use pattern matching and let constructs whenever you can. You are allowed to define “helper” functions (as long as it's using let constructs) to solve these problems and you can include any testing code you develop (although it should be labeled as such). You are expected to use good programming style and to comment each of your functions.

Below is a list of function signatures for the problems in this set:

val sumTo = fn : int -> real

val absList = fn : (int * int) list -> (int * int) list

val split = fn : int list -> (int * int) list

val range = fn : int * int -> int list

val hailstone = fn : int -> int list

val isSorted = fn : int list -> bool

val collapse = fn : int list -> int list

val insert = fn : int * int list -> int list

val isort = fn : int list -> int list

val factors = fn : int -> int list

val change = fn : int list -> int -> int list

Background

Several of these problems mention a precondition for a function.  Such preconditions should always be commented.  When a precondition is violated in ML, the right thing to do (just as it is in Java) is to throw an exception (it’s called raising an exception in ML).  If you want to work on developing good habits by including code to raise an exception when a precondition fails, that would be great.

1.    (5 points) Define a function called sumTo that takes an integer n as an argument and that computes the sum of the first n reciprocals:

For example, sumTo(2) should return 1.5.  The function should return 0.0 if n is 0.  You may assume that the function is not passed a negative value of n.

2.      (5 points) Define a function called absList that takes a list of int * int tuples and that returns a new list of int * int tuples where every integer is replaced by its absolute value.  For example, absList([(~38, 47), (983, ~14), (~17, ~92), (0, 34)]) should return [(38, 47), (983, 14), (17, 92), (0, 34)].  This is easier to solve if you write a helper function to process one tuple.

3.      (10 points) Define a function called split that takes a list of integers as an argument and that returns a list of the tuples obtained by splitting each integer in the list.  Each integer should be split into a pair of integers whose sum equals the integer and which are each half of the original.  For odd numbers, the second value should be one higher than the first.  For example, split([5, 6, 8, 17, 93, 0]) should return [(2, 3), (3, 3), (4, 4), (8, 9), (46, 47), (0, 0)].  You may assume that all of the integers in the list passed to the function are greater than or equal to 0.

4.       (10 points) Define a function called range that takes two integers x and y as arguments and that returns a list composed of the sequence of consecutive integers starting with x and ending with y.  For example, range(18, 23) should return [18, 19, 20, 21, 22, 23] and range(~7, ~7) should return [~7].  If there are no integers in the range, as in the call range(5, 1), the function should return an empty list.

5.       (10 points) Define a function called hailstone that takes an integer n as an argument and that returns the hailstone sequence starting with n and ending with 1.  In the hailstone sequence, each integer n is followed by:

·         n/2 if n is even

·         3n + 1 if n is odd

The sequences are called hailstone sequences because they rise and fall somewhat unpredictably.  It is conjectured that all such sequences for positive integers eventually reach the value 1, at which point they start to repeat the sequence 1, 4, 2, 1, 4, 2, 1, 4, 2, and so on.  Your function should return the list of integers obtained by computing the sequence until it reaches 1.  For example, hailstone(7) should return [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1].  The call hailstone(1) should return [1].  You may assume that the value passed to the function is greater than 0.

6.   (10 points) Define a function isSorted that takes a list of integers and that returns whether or not the list is in sorted (nondecreasing) order (true if it is, false if it is not).  By definition, the empty list and a list of one element are considered to be sorted.

7.  (10 points) Define a function called collapse that takes a list of integers as an argument and that returns the list obtained by collapsing successive pairs in the original list by replacing each pair with its sum.  For example, collapse([1, 3, 5, 19, 7, 4]) should return [4, 24, 11] because the first pair (1 and 3) is collapsed into its sum (4), the second pair (5 and 19) is collapsed into its sum (24) and the third pair (7 and 4) is collapsed into its sum (11).  If the list has an odd length, the final number in the list is not collapsed.  For example, collapse([1, 2, 3, 4, 5]) should return [3, 7, 5].

8.  (10 points) Define a function called insert that take an int and a sorted (nondecreasing) int list as parameters and that returns the list obtained by inserting the int into the list so as to preserve sorted order.  For example, insert(8, [1, 3, 7, 9, 22, 38]) should return [1, 3, 7, 8, 9, 22, 38].

9.  (10 points) Define a function isort that takes an int list as a parameter and that returns the list obtained by sorting the list into nondecreasing order.  In writing isort, you should call your insert function from the previous problem.  The result will be an ML solution to the classic insertion sort algorithm.

10.  (10 points) Define a function called factors that takes an integer as an argument and that returns an ordered list of the factors of that integer.  Recall that a factor is a number that goes evenly into another.  For example, the call factors(12) should return[1,2,3,4,6,12].  Your list has to include the factors in increasing order without duplicates.  You may assume that that the value passed to the function is greater than 0.  You might need to write a helper function to solve this task (the helper function might take more than one argument).

11.  (10 points) We consider the problem of giving change using coins and bills from a cash register. We model coins and bills as integers and the cash register as a list of positive integers (possibly with duplicates). The problem becomes one of finding in a given list a sublist of integers that add up to a given target. The simplest algorithm to solve this problem is the following:

Given a list of integers L and a target t:

  1. If the target t is zero, the problem is trivially solved with an empty list.
  2. Otherwise, if the list L is empty, the problem has no solution and the algorithm fails.
  3. Otherwise, pick a number x from L and let L′ be the list of remaining numbers from L after x is removed. If x is larger than t, it is certainly unusable (since all numbers are positive). Discard it and try to make t with L′ through a recursive call. If x is not larger than t, we can try to use it. So, try to make t − x with L′ using a recursive call.
This algorithm uses a programming technique known as backtracking: try something and, if it doesn’t work, backtrack and try something else. In this case, the choice is between two branches: to use x or not. In order to implement backtracking, we need a way for the program to fail and to continue after failure. I'll leave it to you to figure that out.

Write a function change of type int list -> int -> int list that implements the previous algorithm. The function raises an exception CannotChange if the problem has no solution.

For instance:

change [4,2,32,5,7,1,33,4,1,6] 41 may return [4,2,1,33,1] (or some other numbers from the list that add up to 41), while

change [4,2,32,5,7,1,33,4,1,6] 64 should raise the exception CannotChange

Backtracking can be implemented using an exception CannotChange.

Submitting your work

The simplest way to submit your code (saved into one file as hw1.sml) via Moodle.