A *perfect shuffle* of a standard deck of 52 playing cards
consists of cutting the deck in half (so that the first 26 cards are
in one half and the remaining cards are in the other half) and then
interleaving the two groups of cards, so that the cards alternately
come from the two halves, starting with the first card from the first
half. The same principle applies for decks of sizes other than 52,
although one detail arises for decks with an odd number of cards: we
need a convention for what it means to split the deck in half. We'll
assume that the first half gets the extra card, so that in a deck of 5
cards, for example, the first three cards are the first half and the
remaining two cards are the other half.

Magicians and group theorists have figured out that eight perfect
shuffles restores a deck of 52 cards back to its original
configuration. Similar results hold for other sizes of decks, though
the magical *shuffle number* varies with the deck size. In this lab,
you will use ML programming in order to explore perfect shuffles.

In order to run the Standard ML system on one of the MCS department
Linux machines, you should use the `sml`

command in a shell
(terminal) window. This should behave approximately as shown in the
textbook. Be sure to ask for help if you need it. The error messages
are often quite inscrutable. One easy thing to try when faced with a
strange error message is to more fully parenthesize your code. Many
beginners run into trouble because ML's default grouping isn't what
they expect. ML is like ordinary math notation, rather than like
Scheme, in that extra parentheses never hurt.

This lab assignment calls on you to write a number of different
function definitions. Although you could in principle type them
directly into the `sml`

system, you would be better off
putting them in a file and loading that file in, as described on
page 83 of the textbook. Also, be sure you pay attention to the
type that the ML system infers for each function. Make sure you
understand what each type means and why it makes sense. You are to
turn in the code you write and the type that was inferred for each
function. For the last problem, you should turn in the expression
that you evaluated and what its value is. Be sure to test each
function as you write it, although you do not need to turn in any
evidence of your testing.

The obvious representation of a deck of cards is as a list. Later we'll see how the elements of the list can be structured values that contain suits and ranks (for example, a 3 of hearts). For now, it will suffice to just use a list of consecutive integers, such as the list of integers from 1 to 52. That list should be restored to its original order by 8 perfect shuffles, just as much as a list of actual cards would be. To produce lists like this, write a function

`intsFromTo`

. It should take a pair of integers,`low`and`high`, and return an list of consecutive integers in ascending order, namely all those that are greater than or equal to`low`and less than or equal to`high`. (Under some circumstances, this may be an empty list.)For use in selecting the first half of a deck of cards (i.e., a list), define a function,

`take`

, that is passed a pair consisting of a list and the number of elements that should be taken from the front of the list. For example,`take([10,20,30,40,50],3)`

would evaluate to`[10,20,30]`

.For use in selecting the second half of a deck of cards (i.e., a list), define a function,

`drop`

, that is passed a pair consisting of a list and the number of elements that should be dropped from the front of the list. For example,`drop([10,20,30,40,50],3)`

would evaluate to`[40,50]`

.The next function you need to define is one to

`interleave`

a pair of lists. For example,`interleave([1,2],[10,20])`

would evaluate to`[1,10,2,20]`

.Now you can put together

`take`

,`drop`

, and`interleave`

in order to write a function called`shuffle`

that takes a list and returns the result of performing one perfect shuffle on it. I suggest you read Section 7.8 if you haven't yet; you will be able to make good use of a local variable definition. Be sure you get right the case where the length of the list is odd.Now write a

`shuffleNumber`

function that will take an integer (the deck size), make a list that size, and return a count of how many perfect shuffles are needed to return it to a list equal to the original. You could make good use of a nested function definition (Section 7.9.)The approach of testing shuffled lists for equality with the original is perfectly reasonable. However, for the sake of a really good example of where pattern matching is helpful, let's consider an alternative possibility. Given that we start with a list of increasing integers, we could stop when we return to a list that is in increasing order. Write a function

`isInOrder`

that takes a list of integers and returns a boolean indicating whether the list is strictly increasing. Use pattern matching (as described in Chapter 7) to handle three cases: empty lists, one element lists, and lists with at least two elements. (You may also want to go back and look over your earlier function definitions to see if any of them could be cleaned up a bit using pattern matching.)Show how to use

`map`

to find the shuffle numbers for 5, 50, 500, and 5000.

The one remaining order of business is to switch to a more realistic representations of the cards, including suit and rank. I'm planning to use that as an in-class example.