CS 360
Winter 2016
Programming Language Concepts
CS 360-001 Tuesday/Thursday 15:30-16:50 (Rush 014)
CS 360-002 Tuesday/Thursday 14:00-15:20 (Rush 014)
CS 360-003 Tuesday 18:30-21:20 (University Crossings 153)

Instructor:
Geoffrey Mainland
mainland+cs360@drexel.edu
Office: University Crossings 106
Office hours: Mondays 3pm–5pm; Thursdays 5pm–6pm.
Teaching Assistants:
Pavan Kantharaju
Matthew Roll
Warning! This material is for an old version of the course.

In this assignment, you will implement the Luhn algorithm for validating credit card numbers and solve the Tower of Hanoi problem in Haskell. 1

You must implement the functions as specified. You may write other helper functions and define test data in your file, but you may not change the functions’ names or the number or order of arguments.

This assignment is worth 40 points. There are 41 possible points.

Standard homework instructions

Your code must run either on tux or on the course VM using the version of GHC (7.8.3) that we provide.

A solution template is available in the DrexelCS360/homeworks GitHub repository. You should only need to modify the files provided by the template—please do not check in any files beyond those that the template provides.

Your solutions to all problems must be in the file hw5/HW05.hs in your CS360 repository.

You can check that your code compiles by typing make in the hw5 directory. If make does not complete successfully, it means your code does not compile. Code that does not compile will receive a zero.

We have included several test for your convenience. Passing all provided tests does not guarantee full credit, but failing tests does guarantee less than full credit. You can run the tests by typing make run-tests in the hw5 directory.

Problem 1: Implementing the Luhn Algorithm (30 points total)

The Luhn algorithm is used to check the validity of credit card numbers. You can read about it on Wikipedia here. For this problem, you will implement the Luhn algorithm in Haskell. The algorithm encompasses the following steps:

  1. Double the value of every second digit beginning from the right. That is, the last digit is unchanged; the second-to-last digit is doubled; the third-to-last digit is unchanged; and so on. For example, [1,3,8,6] becomes [2,3,16,6].
  2. Add the digits of the doubled values and the undoubled digits from the original number. For example, [2,3,16,6] becomes 2+3+1+6+6 = 18.
  3. Calculate the remainder when the sum is divided by 10. For the above example, the remainder would be 8. If the result equals 0, then the number is valid.

Problem 1.1 (5 points)

We first need to be able to break up a number into its last digit and the rest of the number. Write these functions:

lastDigit :: Integer -> Integer
dropLastDigit :: Integer -> Integer

If you’re stumped, look through some of the arithmetic operators mentioned in the lecture.

Example output:

GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :load HW05.hs
[1 of 1] Compiling HW05             ( HW05.hs, interpreted )
Ok, modules loaded: HW05.
*HW05> lastDigit 123
3
*HW05> lastDigit 0
0
*HW05> dropLastDigit 123
12
*HW05> dropLastDigit 5
0
*HW05>

Problem 1.2 (5 points)

Now, we can break apart a number into its digits. Define the function

toDigits :: Integer -> [Integer]

toDigits should convert positive Integers to a list of digits. (For 0 or negative inputs, toDigits should return the empty list.)

Examples:

toDigits 1234 == [1,2,3,4]
toDigits 0 == []
toDigits (-17) == []

Problem 1.3 (5 points)

Once we have the digits in the proper order, we need to double every other one. Define a function

doubleEveryOther :: [Integer] -> [Integer]

Remember that doubleEveryOther should double every other number beginning from the right, that is, the second-to-last, fourth-to-last, … numbers are doubled. Note that it’s much easier to perform this operation on a list of digits that’s in reverse order. You will likely need helper functions to make this work.

Examples:

doubleEveryOther [8,7,6,5] == [16,7,12,5]
doubleEveryOther [1,2,3] == [1,4,3]

Problem 1.4 (5 points)

The output of doubleEveryOther has a mix of one-digit and two-digit numbers. Define the function

sumDigits :: [Integer] -> Integer

to calculate the sum of all digits.

Example:

sumDigits [16,7,12,5] = 1 + 6 + 7 + 1 + 2 + 5 = 22

Problem 1.5 (10 points)

Define the function

validate :: Integer -> Bool

that indicates whether an Integer could be a valid credit card number. This will use all functions defined in the previous exercises.

Examples:

validate 4012888888881881 = True
validate 4012888888881882 = False

Problem 2: Tower of Hanoi (10 points)

The Tower of Hanoi is a puzzle in which disks of different sizes are stacked on three pegs. The goal is to get from the initial state, in which all disks are stacked on the first peg, to a final state in which all disks are stacked on the second peg. The only rules are:

  1. Only one disk may be moved at a time.
  2. A larger disk can never be stacked on a smaller disk.

The Tower of Hanoi has an elegant recursive solution: to move $n$ disks from peg $A$ to peg $B$,

  1. Move $n-1$ disks from peg $A$ to peg $C$ using peg $B$ as intermediate storage.
  2. Move the $n$th disk from peg $A$ to peg $B$,
  3. Move $n-1$ disks from peg $C$ to peg $B$ using peg $A$ as intermediate storage.

You will define a function hanoi that when given an integer and the names of three pegs, outputs a list of moves necessary to transfer the stack of disks from the first peg to the second.

type Peg = String
type Move = (Peg, Peg)

hanoi :: Integer -> Peg -> Peg -> Peg -> [Move]

Example output in ghci:

> hanoi 2 "a" "b" "c"
[("a","c"), ("a","b"), ("c","b")]

See Wikipedia for a full explanation of the Tower of Hanoi game.

Hints: My solution is two lines: base case and inductive case. You will probably want to use list functions like ++. Read the LYAH Intro to Lists if you haven’t already.

Problem 3: Homework Statistics (1 point)

How long did it take you to complete each problem? Please tell us in a comment in HW05.hs. You must tell us how long each problem took you to receive the point.

Notes

  1. These problems are adapted from Brent Yorgey’s course, “Introduction to Haskell”.