CIS 554 Clojure 1: Exercises
Fall 2016, David Matuszek

# Purposes of this assignment

• To get you started programming in Clojure
• To get you familiar with Clojure syntax
• To get you familiar with the more important list functions.

# Details

Write and test the following functions. Please be sure to get the spelling and capitalization right, and the right number and types of parameters, in order to make testing them feasible.

These are mostly unrelated exercises, to give you some experience with Clojure syntax. The exercises in the first group do not require higher-order functions, the exercises in the second group might be done with higher-order functions, and the exercises in the third group are higher-order functions. Almost all are recursive.

In some cases, for example reversing a list, you may find Clojure functions that already do exactly what you want. (This is certainly true for the functions whose names begin with `my-`.) Please don't use them, but rather write the functions yourself.

Most of these functions are defined to work with lists, because my experience in Lisp has been almost entirely with lists. If your functions works with lists, they will probably also work with other kinds of sequences.

In all cases, assume that the inputs to the function are correct; don't do any error checking.

## First group

You don't need higher-order functions to program these, but if you see an opportunity to use them, go ahead. Generally, the purpose is to get you used to writing recursive functions the Clojure way.

`(atomic? v)`
Returns `true` if `v` is not any kind of a collection (check with `coll?`), and `false` otherwise.
`(member? x lst)`
Returns a true value if `x` is in `lst`.
`(my-count lst)`
Returns the number of "top level" elements in `lst`. For example, `(a (b c (d e)) f)` has 3 top level elements; `(b c (d e))` is a single top-level element. `(a b () d)` has 4 top-level elements.
`(append lst1 lst2)`
Combine `lst1` and `lst2` into a single list. For example, if `lst1` is ```(:a :b :c) ```and `lst2` is `(1 (2 3))`, the result should be `(:a :b :c 1 (2 3))`.
`(zip lst1 lst2)`
Combine corresponding elements of `lst1` and `lst2` into a list of two-element lists; stop when you run out of elements in either list. For example, if `lst1` is ```(:a :b :c) ```and `lst2` is ```(1 (2 3) 4 5)```, the result should be ```((:a 1) (:b (2 3)) (:c 4))```.
`(lookup key list-of-pairs)`
Given an S-expression `key` and a list of ```(key value)``` pairs, return the `value` that corresponds to the `key`, or `nil` if there is no such pair. You can assume that there is only one such pair.
`(my-merge lst1 lst2)`
Given two lists of integers, where each list is in ascending order, merge them into a single list that is also in ascending order. For example, if `lst1` is `(3 7 12 19 19 25 30)` and `lst2` is `(4 7 10 12 20)`, the result should be `(3 4 7 7 10 12 12 19 19 20 25 30)`.
`(count-all lst)`
Returns the total number of atomic elements in `lst`, at all levels. For example, `(a (b c () (25) nil) ())` has 5 atomic elements: `a`, `b`, `c`, `25`, and `nil`.
`(my-drop n lst)`
Returns the `lst` with the first `n` elements removed. For example, `(my-drop 3 '(a b c d e))` should return `(d e))`. If `n` is equal to or greater than the length of the list `lst`, return the empty list, `()`.
`(my-take n lst)`
Returns a list of the first `n` elements of `lst`. If `lst` has fewer than `n` elements, the result is just `lst`. Strong hint: Use two parameters lists, the second one using an "accumulator" parameter to collect the elements taken from `lst`. You are likely to find `reverse` to be useful.
`(my-reverse lst)`
Reverses the elements of list `lst`. For example, the list `(1 2 (3 4)) `becomes the sequence ```((3 4) 2 1)```.
`(remove-duplicates lst)`
Removes duplicate top-level elements of `lst`. For example, given `(1 2 3 1 4 1 2)`,``` remove-duplicates ```returns a sequence containing the elements ```(1 2 3 4)```, in some order.
`(my-flatten list-of-lists)`
Removes one level of parentheses (or brackets) removed, returning a "flatter" list of values. For example, if` lst` is `(((1 1) (2 3)) ((5 7)))`, the result should be `((1 1) (2 3) (5 7))`.

## Second group

These are best done with higher-order functions, so please use them wherever they seem to work.

`(buzz list-of-ints)`
Return the same list of integers as given as an argument, except that every number divisible by 7, or containing the digit `7`, has been replaced by` :buzz`. Hint: ```(seq string)``` returns a list of characters, and `map` is useful.
`(divisors-of n)`
For positive integer `n`, returns the divisors of `n`, other than 1 and `n` itself. For example, 12 has divisors (`2, 3, 4, 6)`. Hint: Use `mod` and `filter`.
`(longest list-of-strings)`
Returns the longest string in the `list-of-strings`; if there is more than one longest string, return the earlier one. Assume that `list-of-strings` is not empty. Hint: `reduce`.

## Third group

These are your versions of the most commonly used higher-order functions.
`(my-map f lst)`
Apply the function `f`` `to each element of `lst`, returning a list of the results.
`(my-filter pred lst)`
Apply the test `pred `to each element of `lst`, returning a list of the ones that pass the test.
`(my-reduce ``f`` value? lst)`
Applies the two-parameter function `f` to the `value?` and the first element of the sequence (if `value?` is present), else to the first two elements of the sequence; applies the function to the result and the next element in the list, recursively. Hint: Since this function takes two or three arguments, you have to use the proper syntax for this. See Defining and calling functions in my Concise Guide to Clojure.
`(my-flat-map f lst)`
`f` must be a function that returns lists. `my-flat-map` applies the function `f `to each element of `lst`, flattens the resultant list by removing one level of parentheses, and returns the result.

## Unit testing

Write, in a separate file, unit tests for all your methods. Since we haven't talked about testing yet, here's a model for you to follow. Notice the use of `deftest` and `is`.

``````(ns user (:use clojure.test))

(deftest test-my-reverse
(is (= '(3 2 1) (my-reverse '(1 2 3))))
(is (= '(5 (3 4) 2 1) (my-reverse '(1 2 (3 4) 5))))
(is (= () (my-reverse ()))) )

(run-tests)``````

# Due date:

Zip and turn in your` exercises.clj `and``` exercises-test.clj ```files by 6am, Tuesday, September 27 As always, only files submitted to Canvas will be accepted. I do not accept assignments submitted by email.