Code
(* Dan Grossman, Coursera PL, HW2 Provided Code *) (* if you use this function to compare two strings (returns true if the same string), then you avoid several of the functions in problem 1 having polymorphic types that may be confusing *) fun same_string(s1 : string, s2 : string) = s1 = s2 (* put your solutions for problem 1 here *) fun all_except_option (str : string, xs : string list) = let fun isInside (xs : string list) = case xs of [] => false | x::xs' => if same_string(str,x) then true else isInside(xs') fun all_except_option_help (xs : string list, ys: string list) = case xs of [] => ys | x::xs' => if same_string(str, x) then all_except_option_help (xs', ys) else all_except_option_help (xs', ys@[x]) in case isInside(xs) of false => NONE | true => SOME(all_except_option_help(xs, [])) end fun get_substitutions1 (strlistlist : string list list, s : string ) = case strlistlist of [] => [] | strlist::strlistlist' => let val res = all_except_option (s, strlist) in case res of NONE => get_substitutions1 (strlistlist', s) | SOME reslist => reslist @ get_substitutions1 (strlistlist', s) end fun get_substitutions2 (strlistlist : string list list, s : string ) = let fun get_substitutions2_helper (strlistlist : string list list, acc : string list) = case strlistlist of [] => acc | strlist::strlistlist' => let val res = all_except_option (s, strlist) in case res of NONE => get_substitutions2_helper (strlistlist', acc) | SOME reslist => get_substitutions2_helper (strlistlist', acc@reslist) end in get_substitutions2_helper (strlistlist, []) end fun similar_names (strlistlist : string list list, fullname : {first:string, middle:string, last:string} ) = let val {first=x, middle=y, last=z} = fullname val firstnamelist = get_substitutions2 (strlistlist, x) fun similar_names_helper (firstnamelist : string list, fullnamelist : {first:string, last:string, middle:string} list) = case firstnamelist of [] => fullnamelist | firstname::firstnamelist' => similar_names_helper(firstnamelist', fullnamelist @ [ {first = firstname, last = z, middle = y}]) in similar_names_helper(firstnamelist, [{first = x, last = z, middle = y}]) end (* you may assume that Num is always used with values 2, 3, ..., 9 though it will not really come up *) datatype suit = Clubs | Diamonds | Hearts | Spades datatype rank = Jack | Queen | King | Ace | Num of int type card = suit * rank datatype color = Red | Black datatype move = Discard of card | Draw exception IllegalMove (* put your solutions for problem 2 here *) fun card_color (c : card ) = let val (s, r) = c in case s of Spades => Black | Clubs => Black | Diamonds => Red | Hearts => Red end fun card_value (c : card ) = let val (s, r) = c in case r of Ace => 11 | Jack => 10 | Queen => 10 | King => 10 | Num(num) => num end fun remove_card (cs : card list, c: card, e) = let fun isInside (xs : card list) = case xs of [] => false | x::xs' => if x = c then true else isInside(xs') fun remove_card_helper (xs : card list, result : card list) = case xs of [] => result | x::xs' => if (c = x) then result @ xs' else remove_card_helper(xs', result @ [x]) in if (isInside(cs)) then remove_card_helper (cs, []) else raise e end fun all_same_color (cs : card list) = case cs of [] => true | _::[] => true | head :: (neck :: rest) => ((card_color(head) = card_color(neck)) andalso all_same_color(neck :: rest)) fun sum_cards (cs : card list) = let fun sum_cards_helper (cs : card list, acc : int) = case cs of [] => acc | c::cs' => sum_cards_helper(cs', acc + card_value(c)) in sum_cards_helper(cs, 0) end fun score (cs : card list, goal : int) = let val s = sum_cards (cs) val pScore = if (s > goal) then 3*(s - goal) else (goal - s) val result = if (all_same_color(cs)) then (pScore div 2) else pScore in result end fun officiate (cardlist : card list, movelist : move list, goal : int) = let fun officiate_helper (cardlist : card list, movelist : move list, heldcards : card list) = case movelist of [] => heldcards | move::movelist' => case move of Draw => ( case cardlist of [] => heldcards | card::cardlist' => if (sum_cards (card :: heldcards) > goal) then card :: heldcards else officiate_helper(cardlist', movelist', card :: heldcards) ) | Discard c => remove_card(heldcards, c, IllegalMove) in score(officiate_helper (cardlist, movelist, []), goal) end
Test Cases
(* Dan Grossman, Coursera PL, HW2 Provided Tests *) (* These are just two tests for problem 2; you will want more. Naturally these tests and your tests will use bindings defined in your solution, in particular the officiate function, so they will not type-check if officiate is not defined. *) fun provided_test1 () = (* correct behavior: raise IllegalMove *) let val cards = [(Clubs,Jack),(Spades,Num(8))] val moves = [Draw,Discard(Hearts,Jack)] in officiate(cards,moves,42) end fun provided_test2 () = (* correct behavior: return 3 *) let val cards = [(Clubs,Ace),(Spades,Ace),(Clubs,Ace),(Spades,Ace)] val moves = [Draw,Draw,Draw,Draw,Draw] in officiate(cards,moves,42) end val all_except_option_test = all_except_option("a", ["b","c","d","e","f"]); val get_substitutions1_test = get_substitutions2([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],"Fred"); val get_substitutions1_test = get_substitutions2([["Fred","Fredrick"],["Jeff","Jeffrey"],["Geoff","Jeff","Jeffrey"]],"Jeff"); val similar_names_test = similar_names([["Fred","Fredrick"],["Elizabeth","Betty"],["Freddie","Fred","F"]],{first="Fred", middle="W", last="Smith"}); val card_color_test = card_color((Clubs,Jack)); val card_value_test = card_value((Clubs,Jack)); val cards = [(Clubs,Jack),(Spades,Num(8))] val remove_card_test = remove_card ([(Clubs,Jack),(Spades,Num(8))], (Spades,Num(7)), IllegalMove); val all_same_color_test = all_same_color([(Clubs,Jack),(Spades,Num(8))]); val sum_cards_test = sum_cards([(Clubs,Jack),(Spades,Num(8))]); val score_test = score([(Clubs,Jack),(Spades,Num(8))], 10);