csci2041/public-class-repo/SamplePrograms/Sec_10_3:35pm/subsetsum_cps.ml
Michael Zhang 399845160c
f
2018-01-29 17:35:31 -06:00

121 lines
3.4 KiB
OCaml

(* ---
Continuation Passing Style
---
*)
(* First, a function for converting lists into strings *)
let show_list show l =
let rec sl l =
match l with
| [] -> ""
| [x] -> show x
| x::xs -> show x ^ "; " ^ sl xs
in "[ " ^ sl l ^ " ]"
(* Now is_elem which are used in processing the solution *)
let is_elem v l =
List.fold_right (fun x in_rest -> if x = v then true else in_rest) l false
let rec explode = function
| "" -> []
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
let rec implode = function
| [] -> ""
| c::cs -> String.make 1 c ^ implode cs
(* We use a sum function below, so we'll bring in the needed functions
for that. *)
let sum xs = List.fold_left (+) 0 xs
(* Continuation passing style is a style of writing programs in which
the computation that happens after a function returns is packaged
as a function and passed to that function instead where it is
called directly.
In CPS, functions do not return. The computation that happens next
is passed along as an argument in the form of a continuation
function.
In the subsetsum problem we pass two continuations, one to evaluate
if we succeed and find a subset that sums to 0, and another one in
the case in which we fail and reach a deadend in the search
process.
*)
let rec process_solution_cps_v1 show s succ fail =
print_endline ("Here is a solution: \n" ^ show s) ;
print_endline ("Do you like it?");
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
| true -> succ ()
| false -> fail ()
let rec try_subset_cps_v1 partial_subset rest_of_the_set succ fail =
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
then process_solution_cps_v1 (show_list string_of_int)
partial_subset succ fail
else match rest_of_the_set with
| [] -> fail ()
| x::xs ->
try_subset_cps_v1
(partial_subset @ [x]) xs
succ
(fun () -> try_subset_cps_v1 partial_subset xs succ fail)
(* Here the failure continuation will try to other
possibility of not including x in the partial subset.*)
let subsetsum_cps_v1 (lst: int list) =
try_subset_cps_v1
[] lst
(* Our success and failure continuations just print a message. *)
(fun () -> print_endline "Yeah, we found one")
(fun () -> print_endline "Oh no, no subset found.")
(* Another version in which the success continuation takes the chosen
subset as an argument.
*)
let rec process_solution_cps_v2 show s succ fail =
print_endline ( "Here is a solution:\n" ^ show s) ;
print_endline ("Do you like it?") ;
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
| true -> succ s
| false -> fail ()
let rec try_subset_cps_v2 partial_subset rest_of_the_set succ fail =
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
then process_solution_cps_v2 (show_list string_of_int)
partial_subset succ fail
else match rest_of_the_set with
| [] -> fail ()
| x::xs ->
try_subset_cps_v2
(partial_subset @ [x]) xs
succ
(fun () -> try_subset_cps_v2 partial_subset xs succ fail)
let subsetsum_cps_v2 (lst: int list) =
try_subset_cps_v2
[] lst
(fun ss -> print_endline ("Yeah, we found one.\n" ^
"It is as follows:\n" ^
show_list string_of_int ss))
(fun () -> print_endline "Oh no, no subset found.")