In this assignment you will take your first steps in functional programming by writing a few functions that every beginning functional programmer writes. You’ll also gain some familiarity with Scala’s List
class and polymorphic functions. Finally, you’ll see that you can implement any algorithm using only two constructs: if
expressions and recursion.
The first 100 points of this assignment are relatively straightforward, but you may find the last four functions quite challenging. That’s fine. You’re developing an entirely new mental model of programming.
A language the doesn’t change the way you think about programming isn’t worth learning. – Paraphrased from Alan Perlis
You are a beginning functional programmer and you want to get a feel for its fundamental concepts and idioms.
Implement the following functions below following these rules:
mergeSort
) must use a recursive local function.if
expression.List
methods are head
, tail
, and ::
(cons
).def length[T](list: List[T]): Int
Return the number of elements in list
.
Example:
scala> length(List(1,2,3))
res38: Int = 3
def find[T](item: T, list: List[T]): Int
Return the index of item
in list
, or -1
if item
is not in list
.
Example:
scala> find(0, List(1,2,3,4))
res0: Int = -1
scala> find(2, List(1,2,3,4))
res1: Int = 1
def reverse[T](list: List[T]): List[T]
Return a new List
with the same elements as list
, but in reverse order.
Hint: list.head
returns a reference the the first element of a list. x::xs
puts x
at the front of a new list containing x
and the elements of xs
. So (x::xs).head == x
.
Example:
scala> reverse(List(1,2,3,4))
res2: List[Int] = List(4, 3, 2, 1)
def map[T, U](fn: T => U, list: List[T]): List[U]
Return a new List
which collects, in corresponding positions, the results of applying fn
to each element in list
.
Example:
scala> map((x: Int) => 2 * x, List(1,2,3,4))
res3: List[Int] = List(2, 4, 6, 8)
filter[T](fn: T => Boolean, list: List[T]): List[T]
Return a new List
which contains elements e
in list
for which fn(e)
returns true
.
Example:
scala> filter((x: Int) => x % 2 == 0, List(1,2,3,4))
res7: List[Int] = List(2, 4)
def reduce[T](fn: (T, T) => T, list: List[T]): T
Return a new value of type T
which results from applying fn
successively to the elements of list
as follows:
list(0)
as an initial accumulator value, accum
.fn(accum, list(i))
for i = 1
to produce a new accum
value.accum
as the result value of the reduction.Note that the explanation above uses indexes to be clear about the process, but you may not use index operations. Here’s another explanation of reduce
using the recursive structure of lists:
Sarting with list.tail
as the starting list lst
and list.head
as an accummulator value,
lst == Nil
, return the accumulatorlist.tail
as lst
and fn(accum, list.head)
as the accumulator value.The description above probably gave it away. :)
reduce
is a special case offold
for non-empty lists usinglist.head
as the “zero” value and folding intolist.tail
. You’ll learn what this means later.
Example:
scala> reduce((x: Int, y: Int) => x + y, List(1,2,3,4))
res4: Int = 10
scala> reduce((x: String, y: String) => x + y, List("Honey", "Boo", "Boo"))
res5: String = HoneyBooBoo
concat[T](list1: List[T], list2: List[T]): List[T]
Return a new List
which contains all the elements of list1
followed by all the elements of list2
.
Example:
scala> concat(List(1,2,3), List(4,5,6))
res13: List[Int] = List(1, 2, 3, 4, 5, 6)
def merge[T](list1: List[T], list2: List[T])(implicit ordering: Ordering[T]): List[T]
Return a new List
with all the elements in list1
and list2
but in ascending sorted order.
Note: to make the comparison of elements convenient using the <
operator, you’ll need to use an advanced feature known as type classes. We’ll learn about type classes later, but for now, use this stub as a starter for your merge
function:
def merge[T](list1: List[T], list2: List[T])(implicit ordering: Ordering[T]): List[T] = {
import ordering.mkOrderingOps // This import adds <, >, etc. To instances of T
??? // The rest is up to you.
}
Example:
scala> merge(List(1,3,5), List(2,3,4))
res41: List[Int] = List(1, 2, 3, 3, 4, 5)
def mergeSort[T](list: List[T])(implicit ordering: Ordering[T]): List[T]
Return a new List
with all the elements in list
but in ascending sorted order using the merge sort algorithm. Merge sort is a recursive divide-and-conquer algorithm:
To simplify the writing of this method, you may use the following List
method on list
:
length
drop
take
You may also store intermediate values in val
s. For example (hint!):
val left = list.take(list.length / 2)
Note that mergeSort
is itself recursive. You don’t need a local helper function.
Example:
scala> merge(List(1,3,5), List(2,3,4))
res41: List[Int] = List(1, 2, 3, 3, 4, 5)
20 points per function. That’s right, there’s 80 points of extra credit. But you’ll find the last 80 points quite challenging.
Submit your listutils.scala
file on Canvas as an attachment. When you’re ready, double-check that you have submitted and not just saved a draft.
Practice safe submission! Verify that your HW files were truly submitted correctly, the upload was successful, and that your program runs with no syntax or runtime errors. It is solely your responsibility to turn in your homework and practice this safe submission safeguard. NOTE: Unlike TSquare, Canvas will not send an email indicating that your assignment has been submitted successfully. Follow the steps outlined below to ensure you have submitted correctly.
This procedure helps guard against a few things.