Difference between revisions of "Card Game Assignment"

From CSE425S Wiki
Jump to navigation Jump to search
 
(25 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
[https://www.coursera.org/learn/programming-languages/supplement/rhPuJ/hints-and-gotchas-for-homework-2 Hints and Gotchas] credit to [https://vault.hanover.edu/~skiadas/ Charilaos Skiadas]
 
[https://www.coursera.org/learn/programming-languages/supplement/rhPuJ/hints-and-gotchas-for-homework-2 Hints and Gotchas] credit to [https://vault.hanover.edu/~skiadas/ Charilaos Skiadas]
  
=Instructions=
+
=Credit=
 
{{GrossmanCredit}}
 
{{GrossmanCredit}}
  
Line 8: Line 8:
  
 
=Code To Implement=
 
=Code To Implement=
 +
{{SMLToImplement|uw2|all_except_option<br/>get_substitutions1<br/>get_substitutions2<br/>similar_names<br/>card_color<br/>card_value<br/>remove_card<br/>all_same_color<br/>sum_cards<br/>score<br/>officiate<br/>score_challenge<br/>officiate_challenge<br/>careful_player|uw2}}
 +
 
You will write 11 SML functions (not counting local helper functions), 4 related to “name substitutions”
 
You will write 11 SML functions (not counting local helper functions), 4 related to “name substitutions”
 
and 7 related to a made-up solitaire card game.
 
and 7 related to a made-up solitaire card game.
Line 33: Line 35:
 
some list in substitutions that also has s, but s itself should not be in the result. Example:
 
some list in substitutions that also has s, but s itself should not be in the result. Example:
  
<nowiki>get_substitutions1([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],"Fred")
+
<syntaxhighlight lang="sml">
(* answer: ["Fredrick","Freddie","F"] *)</nowiki>
+
get_substitutions1([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],"Fred")
 +
(* answer: ["Fredrick","Freddie","F"] *)
 +
</syntaxhighlight>
  
 
Assume each list in substitutions has no repeats. The result will have repeats if s and another string are
 
Assume each list in substitutions has no repeats. The result will have repeats if s and another string are
 
both in more than one list in substitutions. Example:
 
both in more than one list in substitutions. Example:
  
<nowiki>get_substitutions1([["Fred","Fredrick"],["Jeff","Jeffrey"],["Geoff","Jeff","Jeffrey"]], "Jeff")
+
<syntaxhighlight lang="sml">
(* answer: ["Jeffrey","Geoff","Jeffrey"] *)</nowiki>
+
get_substitutions1([["Fred","Fredrick"],["Jeff","Jeffrey"],["Geoff","Jeff","Jeffrey"]], "Jeff")
 +
(* answer: ["Jeffrey","Geoff","Jeffrey"] *)
 +
</syntaxhighlight>
  
Use part (a) and ML’s list-append (@) but no other helper functions. Sample solution is around 6 lines.
+
Use part (a) and ML’s [https://smlfamily.github.io/Basis/list.html#SIG:LIST.@:VAL list-append (@)] but no other helper functions. Sample solution is around 6 lines.
  
 
===1c) get_substitutions2===
 
===1c) get_substitutions2===
Line 55: Line 61:
 
or (c). The answer should begin with the original name (then have 0 or more other names). Example:
 
or (c). The answer should begin with the original name (then have 0 or more other names). Example:
  
<nowiki>similar_names([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],{first="Fred", middle="W", last="Smith"})
+
<syntaxhighlight lang="sml">
 +
similar_names([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],{first="Fred", middle="W", last="Smith"})
 
(* answer: [{first="Fred", last="Smith", middle="W"},
 
(* answer: [{first="Fred", last="Smith", middle="W"},
 
             {first="Fredrick", last="Smith", middle="W"},
 
             {first="Fredrick", last="Smith", middle="W"},
 
             {first="Freddie", last="Smith", middle="W"},
 
             {first="Freddie", last="Smith", middle="W"},
             {first="F", last="Smith", middle="W"}] *)</nowiki>
+
             {first="F", last="Smith", middle="W"}] *)
 +
</syntaxhighlight>
  
 
Do not eliminate duplicates from the answer. Hint: Use a local helper function. Sample solution is around 10 lines.
 
Do not eliminate duplicates from the answer. Hint: Use a local helper function. Sample solution is around 10 lines.
Line 67: Line 75:
 
tracks the progress of a game; writing a game player is a challenge problem. You can do parts (a)–(e) before
 
tracks the progress of a game; writing a game player is a challenge problem. You can do parts (a)–(e) before
 
understanding the game if you wish.
 
understanding the game if you wish.
 +
 
A game is played with a card-list and a goal. The player has a list of held-cards, initially empty. The player
 
A game is played with a card-list and a goal. The player has a list of held-cards, initially empty. The player
 
makes a move by either drawing, which means removing the first card in the card-list from the card-list and
 
makes a move by either drawing, which means removing the first card in the card-list from the card-list and
Line 72: Line 81:
 
ends either when the player chooses to make no more moves or when the sum of the values of the held-cards
 
ends either when the player chooses to make no more moves or when the sum of the values of the held-cards
 
is greater than the goal.
 
is greater than the goal.
 +
 
The objective is to end the game with a low score (0 is best). Scoring works as follows: Let sum be the sum
 
The objective is to end the game with a low score (0 is best). Scoring works as follows: Let sum be the sum
 
of the values of the held-cards. If sum is greater than goal, the preliminary score is three times (sum−goal),
 
of the values of the held-cards. If sum is greater than goal, the preliminary score is three times (sum−goal),
Line 79: Line 89:
  
 
===2a) card_color===
 
===2a) card_color===
Write a function card_color, which takes a card and returns its color (spades and clubs are black,
+
Write a function <code>card_color</code>, which takes a card and returns its [https://en.wikipedia.org/wiki/Standard_52-card_deck#SVG color] (spades and clubs are black,
 
diamonds and hearts are red). Note: One case-expression is enough.
 
diamonds and hearts are red). Note: One case-expression is enough.
  
 
===2b) card_value===
 
===2b) card_value===
Write a function card_value, which takes a card and returns its value (numbered cards have their
+
Write a function <code>card_value</code>, which takes a card and returns its value (numbered cards have their
 
number as the value, aces are 11, everything else is 10). Note: One case-expression is enough.
 
number as the value, aces are 11, everything else is 10). Note: One case-expression is enough.
  
 
===2c) remove_card===
 
===2c) remove_card===
Write a function remove_card, which takes a list of cards cs, a card c, and an exception e. It returns a
+
Write a function <code>remove_card</code>, which takes a list of cards cs, a card c, and an exception e. It returns a
 
list that has all the elements of cs except c. If c is in the list more than once, remove only the first one.
 
list that has all the elements of cs except c. If c is in the list more than once, remove only the first one.
 
If c is not in the list, raise the exception e. You can compare cards with =.
 
If c is not in the list, raise the exception e. You can compare cards with =.
  
 
===2d) all_same_color===
 
===2d) all_same_color===
Write a function all_same_color, which takes a list of cards and returns true if all the cards in the
+
Write a function <code>all_same_color</code>, which takes a list of cards and returns true if all the cards in the
 
list are the same color. Hint: An elegant solution is very similar to one of the functions using nested
 
list are the same color. Hint: An elegant solution is very similar to one of the functions using nested
 
pattern-matching in the lectures.
 
pattern-matching in the lectures.
  
 
===2e) sum_cards===
 
===2e) sum_cards===
Write a function sum_cards, which takes a list of cards and returns the sum of their values. Use a locally
+
Write a function <code>sum_cards</code>, which takes a list of cards and returns the sum of their values. Use a locally
 
defined helper function that is tail recursive. (Take “calls use a constant amount of stack space” as a
 
defined helper function that is tail recursive. (Take “calls use a constant amount of stack space” as a
 
requirement for this problem.)
 
requirement for this problem.)
  
 
===2f) score===
 
===2f) score===
Write a function score, which takes a card list (the held-cards) and an int (the goal) and computes
+
Write a function <code>score</code>, which takes a <code>card list</code> (the held-cards) and an <code>int</code> (the goal) and computes
 
the score as described above.
 
the score as described above.
  
 
===2g) officiate===
 
===2g) officiate===
Write a function officiate, which “runs a game.” It takes a card list (the card-list) a move list
+
Write a function <code>officiate</code>, which “runs a game.” It takes a <code>card list</code> (the card-list) a <code>move list</code>
 
(what the player “does” at each point), and an int (the goal) and returns the score at the end of the
 
(what the player “does” at each point), and an int (the goal) and returns the score at the end of the
 
game after processing (some or all of) the moves in the move list in order. Use a locally defined recursive
 
game after processing (some or all of) the moves in the move list in order. Use a locally defined recursive
Line 114: Line 124:
 
* The game starts with the held-cards being the empty list.
 
* The game starts with the held-cards being the empty list.
 
* The game ends if there are no more moves. (The player chose to stop since the move list is empty.)
 
* The game ends if there are no more moves. (The player chose to stop since the move list is empty.)
* If the player discards some card c, play continues (i.e., make a recursive call) with the held-cards
+
* If the player discards some card c, play continues (i.e., make a recursive call) with the held-cards not having c and the card-list unchanged. If c is not in the held-cards, raise the IllegalMove exception.
not having c and the card-list unchanged. If c is not in the held-cards, raise the IllegalMove
+
* If the player draws and the card-list is (already) empty, the game is over. Else if drawing causes the sum of the held-cards to exceed the goal, the game is over (after drawing). Else play continues with a larger held-cards and a smaller card-list.
exception.
 
* If the player draws and the card-list is (already) empty, the game is over. Else if drawing causes
 
the sum of the held-cards to exceed the goal, the game is over (after drawing). Else play continues
 
with a larger held-cards and a smaller card-list.
 
  
 
Sample solution for (g) is under 20 lines.
 
Sample solution for (g) is under 20 lines.
Line 125: Line 131:
 
==Challenge Problems==
 
==Challenge Problems==
 
===3a) score_challenge and officiate_challenge===
 
===3a) score_challenge and officiate_challenge===
Write score_challenge and officiate_challenge to be like their non-challenge counterparts except
+
Write <code>score_challenge</code> and <code>officiate_challenge</code> to be like their non-challenge counterparts except
each ace can have a value of 1 or 11 and score_challenge should always return the least (i.e., best)
+
each ace can have a value of 1 or 11 and <code>score_challenge</code> should always return the least (i.e., best)
 
possible score. (Note the game-ends-if-sum-exceeds-goal rule should apply only if there is no sum that
 
possible score. (Note the game-ends-if-sum-exceeds-goal rule should apply only if there is no sum that
 
is less than or equal to the goal.) Hint: This is easier than you might think.
 
is less than or equal to the goal.) Hint: This is easier than you might think.
 +
 
===3b) careful_player===
 
===3b) careful_player===
Write careful_player, which takes a card-list and a goal and returns a move-list such that calling
+
Write <code>careful_player</code>, which takes a card-list and a goal and returns a move-list such that calling
 
officiate with the card-list, the goal, and the move-list has this behavior:
 
officiate with the card-list, the goal, and the move-list has this behavior:
The value of the held cards never exceeds the goal.
+
 
A card is drawn whenever the goal is more than 10 greater than the value of the held cards. As a
+
* The value of the held cards never exceeds the goal.
detail, you should (attempt to) draw, even if no cards remain in the card-list.
+
* A card is drawn whenever the goal is more than 10 greater than the value of the held cards. As a detail, you should (attempt to) draw, even if no cards remain in the card-list.
If a score of 0 is reached, there must be no more moves.
+
* If a score of 0 is reached, there must be no more moves.
If it is possible to reach a score of 0 by discarding a card followed by drawing a card, then this
+
* If it is possible to reach a score of 0 by discarding a card followed by drawing a card, then this must be done. Note careful_player will have to look ahead to the next card, which in many card games is considered “cheating.” Also note that the previous requirement takes precedence: There must be no more moves after a score of 0 is reached even if there is another way to get back to 0.
must be done. Note careful_player will have to look ahead to the next card, which in many card
+
 
games is considered “cheating.” Also note that the previous requirement takes precedence: There
 
must be no more moves after a score of 0 is reached even if there is another way to get back to 0.
 
 
Notes:
 
Notes:
There may be more than one result that meets the requirements above. The autograder should
+
* There may be more than one result that meets the requirements above. The autograder should work for any correct strategy — it checks that the result meets the requirements.
work for any correct strategy — it checks that the result meets the requirements.
+
* This problem is not a continuation of problem 3(a). In this problem, all aces have a value of 11.
This problem is not a continuation of problem 3(a). In this problem, all aces have a value of 11.
 
  
 
=Type Summary=
 
=Type Summary=
 
Evaluating a correct homework solution should generate these bindings, in addition to the bindings from the
 
Evaluating a correct homework solution should generate these bindings, in addition to the bindings from the
 
code provided to you — but see the important caveat that follows.
 
code provided to you — but see the important caveat that follows.
<nowiki>val all_except_option = fn : string * string list -> string list option
+
 
 +
<syntaxhighlight lang="sml">
 +
val all_except_option = fn : string * string list -> string list option
 
val get_substitutions1 = fn : string list list * string -> string list
 
val get_substitutions1 = fn : string list list * string -> string list
 
val get_substitutions2 = fn : string list list * string -> string list
 
val get_substitutions2 = fn : string list list * string -> string list
Line 158: Line 164:
 
val sum_cards = fn : card list -> int
 
val sum_cards = fn : card list -> int
 
val score = fn : card list * int -> int
 
val score = fn : card list * int -> int
val officiate = fn : card list * move list * int -> int</nowiki>
+
val officiate = fn : card list * move list * int -> int
 +
val score_challenge = fn : card list * int -> int
 +
val officiate_challenge = fn : card list * move list * int -> int
 +
val careful_player = fn : card list * int -> move list
 +
</syntaxhighlight>
  
 
=Important Caveat=
 
=Important Caveat=
 
The REPL may give your functions equivalent types or more general types. This is fine. In the sample
 
The REPL may give your functions equivalent types or more general types. This is fine. In the sample
 
solution, the bindings for problems 1d, 2a, 2b, 2c, and 2d were all more general. For example, card_color
 
solution, the bindings for problems 1d, 2a, 2b, 2c, and 2d were all more general. For example, card_color
had type suit * ’a -> color and remove_card had type ’’a list * ’’a * exn -> ’’a list. They
+
had type <code>suit * ’a -> color</code> and remove_card had type <code>’’a list * ’’a * exn -> ’’a list</code>. They
 
are more general, which means there is a way to replace the type variables (’a or ’’a) with types to get the
 
are more general, which means there is a way to replace the type variables (’a or ’’a) with types to get the
bindings listed above. As for equivalent types, because type card = suit*rank, types like card -> int
+
bindings listed above. As for equivalent types, because <code>type card = suit*rank</code>, types like <code>card -> int</code>
and suit*rank->int are equivalent. They are the same type, and the REPL simply chooses one way of
+
and <code>suit*rank->int</code> are equivalent. They are the same type, and the REPL simply chooses one way of
 
printing the type. Also, the order of fields in records never matters.
 
printing the type. Also, the order of fields in records never matters.
 +
 
If you write down explicit argument types for functions, you will probably not see equivalent or more-general
 
If you write down explicit argument types for functions, you will probably not see equivalent or more-general
 
types, but we encourage the common ML approach of omitting all explicit types.
 
types, but we encourage the common ML approach of omitting all explicit types.
 +
 
Of course, generating these bindings does not guarantee that your solutions are correct. Test your functions:
 
Of course, generating these bindings does not guarantee that your solutions are correct. Test your functions:
 
Put your testing code in a second file. We will not grade the testing file, nor will you turn it in, but surely
 
Put your testing code in a second file. We will not grade the testing file, nor will you turn it in, but surely
 
you want to run your functions and record your test inputs in a file.
 
you want to run your functions and record your test inputs in a file.
 +
 +
=Test=
 +
{{SMLUnitTesting|run_uw2_testing|uw2}}
 +
 +
Test your functions.  The unit tests you have been provided by UW are intentionally minimal.
  
 
=Pledge, Acknowledgments, Citations=
 
=Pledge, Acknowledgments, Citations=
{{Pledge|lab-2-card-game-date}}
+
{{Pledge|uw2-card-game}}

Latest revision as of 19:01, 10 July 2023

Hints and Gotchas

Hints and Gotchas credit to Charilaos Skiadas

Credit

All credit for this assignment goes to Prof. Grossman and his team at UW.

UW or Coursera

Code To Implement

file: src/main/sml/uw2/uw2.sml Smlnj-logo.png
functions: all_except_option
get_substitutions1
get_substitutions2
similar_names
card_color
card_value
remove_card
all_same_color
sum_cards
score
officiate
score_challenge
officiate_challenge
careful_player

You will write 11 SML functions (not counting local helper functions), 4 related to “name substitutions” and 7 related to a made-up solitaire card game.

Your solutions must use pattern-matching. You may not use the functions null, hd, tl, isSome, or valOf, nor may you use anything containing a # character or features not used in class (such as mutation). Note that list order does not matter unless specifically stated in the problem.

The sample solution, not including challenge problems, is roughly 130 lines, including the provided code.

first-name substitutions

This problem involves using first-name substitutions to come up with alternate names. For example, Fredrick William Smith could also be Fred William Smith or Freddie William Smith. Only similar_names is specifically about this, but the other problems are helpful.

1a) all_except_option

Write a function all_except_option, which takes a string and a string list. Return NONE if the string is not in the list, else return SOME lst where lst is identical to the argument list except the string is not in it. You may assume the string is in the list at most once. Use same_string, provided to you, to compare strings. Sample solution is around 8 lines.

1b) get_substitutions1

Write a function get_substitutions1, which takes a string list list (a list of list of strings, the substitutions) and a string s and returns a string list. The result has all the strings that are in some list in substitutions that also has s, but s itself should not be in the result. Example:

get_substitutions1([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],"Fred")
(* answer: ["Fredrick","Freddie","F"] *)

Assume each list in substitutions has no repeats. The result will have repeats if s and another string are both in more than one list in substitutions. Example:

get_substitutions1([["Fred","Fredrick"],["Jeff","Jeffrey"],["Geoff","Jeff","Jeffrey"]], "Jeff")
(* answer: ["Jeffrey","Geoff","Jeffrey"] *)

Use part (a) and ML’s list-append (@) but no other helper functions. Sample solution is around 6 lines.

1c) get_substitutions2

Write a function get_substitutions2, which is like get_substitutions1 except it uses a tail-recursive local helper function.

1d) similar_names

Write a function similar_names, which takes a string list list of substitutions (as in get_substitutions1 and get_substitutions2) and a full name of type {first:string,middle:string,last:string} and returns a list of full names (type {first:string,middle:string,last:string} list). The result is all the full names you can produce by substituting for the first name (and only the first name) using substitutions and parts (b) or (c). The answer should begin with the original name (then have 0 or more other names). Example:

similar_names([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],{first="Fred", middle="W", last="Smith"})
(* answer: [{first="Fred", last="Smith", middle="W"},
            {first="Fredrick", last="Smith", middle="W"},
            {first="Freddie", last="Smith", middle="W"},
            {first="F", last="Smith", middle="W"}] *)

Do not eliminate duplicates from the answer. Hint: Use a local helper function. Sample solution is around 10 lines.

solitaire card game

This problem involves a solitaire card game invented just for this question. You will write a program that tracks the progress of a game; writing a game player is a challenge problem. You can do parts (a)–(e) before understanding the game if you wish.

A game is played with a card-list and a goal. The player has a list of held-cards, initially empty. The player makes a move by either drawing, which means removing the first card in the card-list from the card-list and adding it to the held-cards, or discarding, which means choosing one of the held-cards to remove. The game ends either when the player chooses to make no more moves or when the sum of the values of the held-cards is greater than the goal.

The objective is to end the game with a low score (0 is best). Scoring works as follows: Let sum be the sum of the values of the held-cards. If sum is greater than goal, the preliminary score is three times (sum−goal), else the preliminary score is (goal − sum). The score is the preliminary score unless all the held-cards are the same color, in which case the score is the preliminary score divided by 2 (and rounded down as usual with integer division; use ML’s div operator).

2a) card_color

Write a function card_color, which takes a card and returns its color (spades and clubs are black, diamonds and hearts are red). Note: One case-expression is enough.

2b) card_value

Write a function card_value, which takes a card and returns its value (numbered cards have their number as the value, aces are 11, everything else is 10). Note: One case-expression is enough.

2c) remove_card

Write a function remove_card, which takes a list of cards cs, a card c, and an exception e. It returns a list that has all the elements of cs except c. If c is in the list more than once, remove only the first one. If c is not in the list, raise the exception e. You can compare cards with =.

2d) all_same_color

Write a function all_same_color, which takes a list of cards and returns true if all the cards in the list are the same color. Hint: An elegant solution is very similar to one of the functions using nested pattern-matching in the lectures.

2e) sum_cards

Write a function sum_cards, which takes a list of cards and returns the sum of their values. Use a locally defined helper function that is tail recursive. (Take “calls use a constant amount of stack space” as a requirement for this problem.)

2f) score

Write a function score, which takes a card list (the held-cards) and an int (the goal) and computes the score as described above.

2g) officiate

Write a function officiate, which “runs a game.” It takes a card list (the card-list) a move list (what the player “does” at each point), and an int (the goal) and returns the score at the end of the game after processing (some or all of) the moves in the move list in order. Use a locally defined recursive helper function that takes several arguments that together represent the current state of the game. As described above:

  • The game starts with the held-cards being the empty list.
  • The game ends if there are no more moves. (The player chose to stop since the move list is empty.)
  • If the player discards some card c, play continues (i.e., make a recursive call) with the held-cards not having c and the card-list unchanged. If c is not in the held-cards, raise the IllegalMove exception.
  • If the player draws and the card-list is (already) empty, the game is over. Else if drawing causes the sum of the held-cards to exceed the goal, the game is over (after drawing). Else play continues with a larger held-cards and a smaller card-list.

Sample solution for (g) is under 20 lines.

Challenge Problems

3a) score_challenge and officiate_challenge

Write score_challenge and officiate_challenge to be like their non-challenge counterparts except each ace can have a value of 1 or 11 and score_challenge should always return the least (i.e., best) possible score. (Note the game-ends-if-sum-exceeds-goal rule should apply only if there is no sum that is less than or equal to the goal.) Hint: This is easier than you might think.

3b) careful_player

Write careful_player, which takes a card-list and a goal and returns a move-list such that calling officiate with the card-list, the goal, and the move-list has this behavior:

  • The value of the held cards never exceeds the goal.
  • A card is drawn whenever the goal is more than 10 greater than the value of the held cards. As a detail, you should (attempt to) draw, even if no cards remain in the card-list.
  • If a score of 0 is reached, there must be no more moves.
  • If it is possible to reach a score of 0 by discarding a card followed by drawing a card, then this must be done. Note careful_player will have to look ahead to the next card, which in many card games is considered “cheating.” Also note that the previous requirement takes precedence: There must be no more moves after a score of 0 is reached even if there is another way to get back to 0.

Notes:

  • There may be more than one result that meets the requirements above. The autograder should work for any correct strategy — it checks that the result meets the requirements.
  • This problem is not a continuation of problem 3(a). In this problem, all aces have a value of 11.

Type Summary

Evaluating a correct homework solution should generate these bindings, in addition to the bindings from the code provided to you — but see the important caveat that follows.

val all_except_option = fn : string * string list -> string list option
val get_substitutions1 = fn : string list list * string -> string list
val get_substitutions2 = fn : string list list * string -> string list
val similar_names = fn : string list list * {first:string, last:string, middle:string} -> {first:string, last:string, middle:string} list
val card_color = fn : card -> color
val card_value = fn : card -> int
val remove_card = fn : card list * card * exn -> card list
val all_same_color = fn : card list -> bool
val sum_cards = fn : card list -> int
val score = fn : card list * int -> int
val officiate = fn : card list * move list * int -> int
val score_challenge = fn : card list * int -> int
val officiate_challenge = fn : card list * move list * int -> int
val careful_player = fn : card list * int -> move list

Important Caveat

The REPL may give your functions equivalent types or more general types. This is fine. In the sample solution, the bindings for problems 1d, 2a, 2b, 2c, and 2d were all more general. For example, card_color had type suit * ’a -> color and remove_card had type ’’a list * ’’a * exn -> ’’a list. They are more general, which means there is a way to replace the type variables (’a or ’’a) with types to get the bindings listed above. As for equivalent types, because type card = suit*rank, types like card -> int and suit*rank->int are equivalent. They are the same type, and the REPL simply chooses one way of printing the type. Also, the order of fields in records never matters.

If you write down explicit argument types for functions, you will probably not see equivalent or more-general types, but we encourage the common ML approach of omitting all explicit types.

Of course, generating these bindings does not guarantee that your solutions are correct. Test your functions: Put your testing code in a second file. We will not grade the testing file, nor will you turn it in, but surely you want to run your functions and record your test inputs in a file.

Test

source folder: src/test/sml/uw2
how to run with CM.make verbosity off: sml -Ccm.verbose=false run_uw2_testing.sml
how to run with CM.make verbosity on: sml run_uw2_testing.sml

note: ensure that you have removed all printing to receive credit for any assignment.

SML Error Messages

Test your functions. The unit tests you have been provided by UW are intentionally minimal.

Pledge, Acknowledgments, Citations

file: uw2-card-game-pledge-acknowledgments-citations.txt

More info about the Honor Pledge