Skip to content

Instantly share code, notes, and snippets.

@jatesy
Created April 1, 2014 18:21
Show Gist options
  • Save jatesy/9919949 to your computer and use it in GitHub Desktop.
Save jatesy/9919949 to your computer and use it in GitHub Desktop.
A hotel reservation system implemented in functional language(Standard ML)
(*The signature includes the total number of 2-double-bed romms,queen-bed rooms and king-bed rooms accordingly
in a hotel. Also the requirements of minimum number of nights and number limit of occupancy must be met by
any reservation*)
signature ROOMDETAIL =
sig
val doubleAvailable:int;
val queenAvailable:int;
val kingAvailable:int;
val minnights:int option;
val occupancyLimit:int;
end;
(*The functor use a structure with a signature of ROOMDETAIL to build a structure for a specified
hotel,in which the reservation system will be built up*)
functor MakeHotel(Q:ROOMDETAIL):
(*The signature exposes the full details of types resrecord and roomconfig so that the users
can use these definitions. It also exposes the existences of type ressys and other functions *)
sig
datatype roomconfig = DOUBLE_RM | QUEEN_RM | KING_RM;
exception Deny;
type resrecord =
{
id:int,
first_name:string,
last_name:string,
check_in_date:int,
num_of_nights:int,
num_of_occu:int,
rm_config:roomconfig,
num_of_gst:int
};type ressys;
val empty: ressys;
val pred_date: int -> resrecord -> bool;
val length: 'a list -> int;
val filter: ('a -> 'b -> bool) -> 'a -> 'b list -> 'b list;
val exist: int -> resrecord list -> bool;
val reserve: ressys -> resrecord -> ressys;
val cancel: ressys -> int -> ressys;
val getInventory: ressys -> roomconfig -> int -> int;
val getInventorySpan: ressys -> roomconfig -> int -> int ->bool;
val completedStays: ressys -> int -> int;
val removeCompletedStays: ressys -> int -> ressys;
val restrictions: resrecord -> bool;
val guestQuantity: ressys -> int -> int;
val update_reserve: ressys -> resrecord -> ressys;
end = struct
(*The structure defines all the datatypes, exceptions, types and functions with implementation details*)
open Q;
(*Room configuration includes three types of rooms, namely, 2-double-bed romm,queen-bed room and
king-bed room*)
datatype roomconfig = DOUBLE_RM | QUEEN_RM | KING_RM;
(*Whenever an operation is denied by the reservation system, it will raise the exception of Deny*)
exception Deny;
(*type resrecord includes all information needed as a record of reservation*)
type resrecord =
{
id:int,
first_name:string,
last_name:string,
check_in_date:int,
num_of_nights:int,
num_of_occu:int,
rm_config:roomconfig,
num_of_gst:int
};
(*type ressys includes all information needed as a reservation system of a hotel*)
type ressys =
{
double_rm_quantity:int,
queen_rm_quantity:int,
king_rm_quantity:int,
resv_record:resrecord list
};
(*A helper function. Inputs are a date and a reservation record, output is whether the date range of the stay on the
given record includes the given date, as a boolean*)
fun pred_date a (rrc:resrecord) = (#check_in_date rrc) <= a andalso ( (#check_in_date rrc) + (#num_of_nights rrc) ) > a;
(*A helper function, which gets the length of a given list*)
fun length [] = 0
| length(x::xs) = 1 + length xs;
(*A helper funtion. It gets elements for which function pred evaluates to ture from a list. Inputs: a list and a funtion
that returns boolean. Output: a list of elements on given list that can make pred envaluate to ture*)
fun filter pred i [] = []
| filter pred i (r::rl) = if pred i r
then r::(filter pred i rl)
else filter pred i rl;
(*A helper function, which checks if an ID exists on a given list of reservation records. Inputs: a list of reservation
records and an ID. Output: Boolean*)
fun exist x [] = false
| exist x ((y::ys):resrecord list)= if x = (#id y)
then true
else exist x ys;
(*Function empty creats an empty reservation system using the quantity of available hotel rooms for each configiuration in the
signature ROOMDETAIL*)
val empty = { double_rm_quantity = Q.doubleAvailable,queen_rm_quantity = Q.queenAvailable, king_rm_quantity = Q.kingAvailable,
resv_record = [] };
(*Function getInventory gives the number of rooms available to be reserved for the specified configiration for the given date
Input: a reserve system, a room configiration and date. Output:number of available rooms*)
fun getInventory (rsy:ressys) (rmcf:roomconfig) date =
let
fun pred_rmcf a (rrc:resrecord) = a = (#rm_config rrc);
in
if rmcf = DOUBLE_RM
then (#double_rm_quantity rsy) - (length (filter pred_rmcf DOUBLE_RM (filter pred_date date (#resv_record rsy))))
else if rmcf = QUEEN_RM
then (#queen_rm_quantity rsy) - (length (filter pred_rmcf QUEEN_RM (filter pred_date date (#resv_record rsy))))
else (#king_rm_quantity rsy) - (length (filter pred_rmcf KING_RM (filter pred_date date (#resv_record rsy))))
end
(*Function getInventorySpan checks whether the room inventory is available for all nights, given a reservation system,
roomconfiguration, a date and a number of nights
Input:a reservation system, a room configuration, a date and a number of nights. Output:boolean*)
fun getInventorySpan (a_rsy:ressys) rmcf date 0 = true
| getInventorySpan (a_rsy:ressys) rmcf date nights = if getInventory a_rsy rmcf date > 0
then getInventorySpan a_rsy rmcf (date + 1) (nights - 1)
else false;
(*Function restrictions checks whether a reserve record met the requirements of minimum number of nights and the number limit of
occupancy.Input: a reservation record. Output:boolean*)
fun restrictions (rrc:resrecord) =
let
fun getInt NONE = true
| getInt (SOME x) = if (#num_of_nights rrc) < x
then false
else true
in
if (getInt Q.minnights) andalso (Q.occupancyLimit > (#num_of_occu rrc))
then true
else false
end;
(*Function reserve adds a reserve record to a reserve system. Input:a reservation system and a reservation record.
Output: a new reservation system with this record*)
fun reserve (rsy:ressys) (rrc:resrecord) = if (restrictions rrc)
then (if (exist (#id rrc) (#resv_record rsy)) = false andalso (getInventorySpan rsy
(#rm_config rrc) (#check_in_date rrc) (#num_of_nights rrc))
then{ double_rm_quantity = (#double_rm_quantity rsy), queen_rm_quantity =
(#queen_rm_quantity rsy), king_rm_quantity = (#king_rm_quantity rsy),resv_record =
rrc::(#resv_record rsy)}
else raise Deny)
else raise Deny;
(*Function cancel cancels a reserve record from a reserve system. Input:a reservation system and a reservation record.
Output: a new reservation system without this record*)
fun cancel (rsy:ressys) id =
let
fun pred1 id (rrc:resrecord) = id <> (#id rrc);
in
if exist id (#resv_record rsy)
then { double_rm_quantity = (#double_rm_quantity rsy),queen_rm_quantity = (#queen_rm_quantity rsy),
king_rm_quantity = (#king_rm_quantity rsy),resv_record = (filter pred1 id (#resv_record rsy)) }
else raise Deny
end;
(*Function completedStays calculates the number of completed stays due to a given date. Input: a reservation system and a date.
Output: the number of completed stays due to a given date*)
fun completedStays (rsy:ressys) date =
let
fun pred_date2 a (rrc:resrecord) = a > ((#check_in_date rrc) + (#num_of_nights rrc));
in
length (filter pred_date2 date (#resv_record rsy))
end;
(*Function removeCompletedStays removes all completed stays due to a given date.Input: a reservation system and a date.
Output:a new reservation system without all completed stays due to the given date*)
fun removeCompletedStays (rsy:ressys) date =
let
fun pred_date3 a (rrc:resrecord) = a <= ((#check_in_date rrc) + (#num_of_nights rrc));
in
{ double_rm_quantity = (#double_rm_quantity rsy),queen_rm_quantity = (#queen_rm_quantity rsy),king_rm_quantity =
(#king_rm_quantity rsy),resv_record = (filter pred_date3 date (#resv_record rsy)) }
end;
(*Function guestQuantity calculates the total number of guests in the hotel on a given date. Input: a reservation system and a date
Output: total number of guests in the hotel on the given date*)
fun guestQuantity (rsy:ressys) date =
let
val rrc_list = filter pred_date date (#resv_record rsy)
fun getQ [] = 0
| getQ ((y::ys):resrecord list) = (#num_of_gst y) + getQ ys
in
getQ rrc_list
end;
(*This is the improvement I have made to the reserve system. If a custtomer wants to update his reservation and change some
information like number of nights he will stay, room configuration or number of occupants. This function called
update_reserve can easily take care of this. It will first check whether the ID exists on the reserve system and whether
there are enough available rooms for the updating. If so, it will replace the old reserve record with the new one
Input: a reserve system and the new record.
Output: a new reserve system with the new record instead of the old one*)
fun update_reserve (rsy:ressys) (rrc:resrecord) = if (restrictions rrc)
then (if (exist (#id rrc) (#resv_record rsy)) andalso (getInventorySpan (cancel rsy (#id rrc))
(#rm_config rrc) (#check_in_date rrc) (#num_of_nights rrc))
then reserve (cancel rsy (#id rrc)) rrc
else raise Deny)
else raise Deny;
end;
(*Below is the test bed with some comment*)
structure TestHotelRoomDetail : ROOMDETAIL =
struct
val doubleAvailable = 20
val queenAvailable = 1
val kingAvailable = 3
val minnights = SOME 2
val occupancyLimit = 4
end
structure TestHotel = MakeHotel(TestHotelRoomDetail);
exception TestFailed
open TestHotel;
(*Test of creating a reserve system*)
fun testCreateSys () =
let
val hotel = empty;
val double = getInventory hotel DOUBLE_RM 0;
val queen = getInventory hotel QUEEN_RM 0;
val king = getInventory hotel KING_RM 0;
in
if double = 20 andalso queen = 1 andalso king = 3
then print "\nThe hotel reservation system has been created successfully!\n"
else raise TestFailed
end
(*Test of adding reservation records to reserve system*)
fun testReserve () =
let
val emptyHotel = empty;
val record1 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 1};
val record2 = {id = 101, first_name = "B", last_name = "G", check_in_date= 0, num_of_nights = 3, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 3};
val record3 = {id = 102, first_name = "C", last_name = "H", check_in_date= 0, num_of_nights = 4, num_of_occu = 3, rm_config = QUEEN_RM, num_of_gst = 1};
val record4 = {id = 103, first_name = "D", last_name = "I", check_in_date= 0, num_of_nights = 6, num_of_occu = 2, rm_config = KING_RM, num_of_gst = 0};
val record5 = {id = 104, first_name = "E", last_name = "J", check_in_date= 0, num_of_nights = 7, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 2};
val hotelwrc1 = reserve emptyHotel record1;
val hotelwrc2 = reserve hotelwrc1 record2;
val hotelwrc3 = reserve hotelwrc2 record3;
val hotelwrc4 = reserve hotelwrc3 record4;
val hotelwrc5 = reserve hotelwrc4 record5;
val double = getInventory hotelwrc5 DOUBLE_RM 0;
val queen = getInventory hotelwrc5 QUEEN_RM 0;
val king = getInventory hotelwrc5 KING_RM 0;
fun test x = true;
in
if ((test (reserve emptyHotel record1)) handle Deny => false) andalso ((test (reserve hotelwrc1 record2)) handle Deny => false) andalso
((test (reserve hotelwrc2 record3)) handle Deny => false) andalso ((test (reserve hotelwrc3 record4)) handle Deny => false) andalso
((test (reserve hotelwrc4 record5)) handle Deny => false)
then print "\n5 reservations have been added to the hotel reservation system!\n"
else raise TestFailed
end
(*Demonstration of unsuccessful reservation due to lack of inventory*)
fun Demo_lack_inventory () =
let
val emptyHotel = empty;
val record6 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = QUEEN_RM,
num_of_gst = 1};
val record7 = {id = 106, first_name = "K", last_name = "L", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = QUEEN_RM,
num_of_gst = 1};
val hotelwrc6 = reserve emptyHotel record6;
fun test x = false;
in
if ((test (reserve hotelwrc6 record7)) handle Deny => true)
then print "\nDemonstration of unsuccessful reservation due to lack of inventory completed!\n"
else raise TestFailed
end
(*Demonstration of unsuccessful reservation due to room occupancy being exceeding or minimum night requirement not being met*)
fun Demo_restriction () =
let
val emptyHotel = empty;
val record8 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 1, num_of_occu = 5, rm_config = QUEEN_RM, num_of_gst = 1};
fun test x = false;
in
if ((test (reserve emptyHotel record8)) handle Deny => true)
then print "\nDemonstration of unsuccessful reservation due to room occupancy being exceeding or minimum night requirement not being met completed!\n"
else raise TestFailed
end
(*Test of canceling reservation records from the reservation system*)
fun testCancel () =
let
val emptyHotel = empty;
val record1 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 1};
val record2 = {id = 101, first_name = "B", last_name = "G", check_in_date= 0, num_of_nights = 3, num_of_occu = 3, rm_config = QUEEN_RM, num_of_gst = 3};
val record3 = {id = 102, first_name = "C", last_name = "H", check_in_date= 0, num_of_nights = 4, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 1};
val record4 = {id = 103, first_name = "D", last_name = "I", check_in_date= 0, num_of_nights = 6, num_of_occu = 2, rm_config = KING_RM, num_of_gst = 0};
val record5 = {id = 104, first_name = "E", last_name = "J", check_in_date= 0, num_of_nights = 7, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 2};
val hotelwrc1 = reserve emptyHotel record1;
val hotelwrc2 = reserve hotelwrc1 record2;
val hotelwrc3 = reserve hotelwrc2 record3;
val hotelwrc4 = reserve hotelwrc3 record4;
val hotelwrc5 = reserve hotelwrc4 record5;
val hotelwrc6 = cancel hotelwrc5 104;
fun test x = true;
in
if ((test (reserve emptyHotel record1)) handle Deny => false) andalso ((test (reserve hotelwrc1 record2)) handle Deny => false) andalso
((test (reserve hotelwrc2 record3)) handle Deny => false) andalso ((test (reserve hotelwrc3 record4)) handle Deny => false) andalso
((test (reserve hotelwrc4 record5)) handle Deny => false) andalso ((test (cancel hotelwrc5 104)) handle Deny => false) andalso
((test (cancel hotelwrc6 103)) handle Deny => false)
then print "\n2 reservations have been canceled from the hotel reservation system!\n"
else raise TestFailed
end
(*Test of querying room inventory*)
fun queryInventory () =
let
val emptyHotel = empty;
val record1 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 1};
val record2 = {id = 101, first_name = "B", last_name = "G", check_in_date= 0, num_of_nights = 3, num_of_occu = 3, rm_config = DOUBLE_RM, num_of_gst = 3};
val record3 = {id = 102, first_name = "C", last_name = "H", check_in_date= 0, num_of_nights = 4, num_of_occu = 3, rm_config = DOUBLE_RM, num_of_gst = 1};
val record4 = {id = 103, first_name = "D", last_name = "I", check_in_date= 0, num_of_nights = 6, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 0};
val record5 = {id = 104, first_name = "E", last_name = "J", check_in_date= 0, num_of_nights = 7, num_of_occu = 3, rm_config = DOUBLE_RM, num_of_gst = 2};
val hotelwrc1 = reserve emptyHotel record1;
val hotelwrc2 = reserve hotelwrc1 record2;
val hotelwrc3 = reserve hotelwrc2 record3;
val hotelwrc4 = reserve hotelwrc3 record4;
val hotelwrc5 = reserve hotelwrc4 record5;
val double = getInventory hotelwrc5 DOUBLE_RM 0;
in
if double = 15
then print "\nRoom inventory for 2-double-bed room on date 0 has been queried successfully!\n"
else raise TestFailed
end
(*Demostration of removeCompletedStays and completedStays*)
fun Demo_cmplt () =
let
val emptyHotel = empty;
val record1 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 1};
val record2 = {id = 101, first_name = "B", last_name = "G", check_in_date= 0, num_of_nights = 3, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 3};
val record3 = {id = 102, first_name = "C", last_name = "H", check_in_date= 0, num_of_nights = 4, num_of_occu = 3, rm_config = QUEEN_RM, num_of_gst = 1};
val record4 = {id = 103, first_name = "D", last_name = "I", check_in_date= 0, num_of_nights = 6, num_of_occu = 2, rm_config = KING_RM, num_of_gst = 0};
val record5 = {id = 104, first_name = "E", last_name = "J", check_in_date= 0, num_of_nights = 7, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 2};
val hotelwrc1 = reserve emptyHotel record1;
val hotelwrc2 = reserve hotelwrc1 record2;
val hotelwrc3 = reserve hotelwrc2 record3;
val hotelwrc4 = reserve hotelwrc3 record4;
val hotelwrc5 = reserve hotelwrc4 record5
val int1 = completedStays hotelwrc5 5;
val hotelwrc7 = removeCompletedStays hotelwrc5 5;
val int2 = completedStays hotelwrc7 5;
in
if (int1 = 3) andalso (int2 = 0)
then print "\nDemostration of removeCompletedStays and completedStays succeed!\n"
else raise TestFailed
end
(*Demostration of the getting the guest quantity*)
fun Demo_gstQtt () =
let
val emptyHotel = empty;
val record1 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 1};
val record2 = {id = 101, first_name = "B", last_name = "G", check_in_date= 0, num_of_nights = 3, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 3};
val record3 = {id = 102, first_name = "C", last_name = "H", check_in_date= 0, num_of_nights = 4, num_of_occu = 3, rm_config = QUEEN_RM, num_of_gst = 1};
val record4 = {id = 103, first_name = "D", last_name = "I", check_in_date= 0, num_of_nights = 6, num_of_occu = 2, rm_config = KING_RM, num_of_gst = 2};
val record5 = {id = 104, first_name = "E", last_name = "J", check_in_date= 0, num_of_nights = 7, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 3};
val hotelwrc1 = reserve emptyHotel record1;
val hotelwrc2 = reserve hotelwrc1 record2;
val hotelwrc3 = reserve hotelwrc2 record3;
val hotelwrc4 = reserve hotelwrc3 record4;
val hotelwrc5 = reserve hotelwrc4 record5
val int1 = guestQuantity hotelwrc5 1;
in
if (int1 = 10)
then print "\nDemostration of the guestQuantity succeed!\n"
else raise TestFailed
end
(*Test of my own improvement: Updating a reservation record*)
fun testUpdateReserve () =
let
val emptyHotel = empty;
val record1 = {id = 100, first_name = "A", last_name = "F", check_in_date= 0, num_of_nights = 2, num_of_occu = 2, rm_config = DOUBLE_RM, num_of_gst = 1};
val record2 = {id = 101, first_name = "B", last_name = "G", check_in_date= 0, num_of_nights = 3, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 3};
val record3 = {id = 102, first_name = "C", last_name = "H", check_in_date= 0, num_of_nights = 4, num_of_occu = 3, rm_config = QUEEN_RM, num_of_gst = 1};
val record4 = {id = 103, first_name = "D", last_name = "I", check_in_date= 0, num_of_nights = 6, num_of_occu = 2, rm_config = KING_RM, num_of_gst = 2};
val record5 = {id = 104, first_name = "E", last_name = "J", check_in_date= 0, num_of_nights = 7, num_of_occu = 3, rm_config = KING_RM, num_of_gst = 3};
val hotelwrc1 = reserve emptyHotel record1;
val hotelwrc2 = reserve hotelwrc1 record2;
val hotelwrc3 = reserve hotelwrc2 record3;
val hotelwrc4 = reserve hotelwrc3 record4;
val hotelwrc5 = reserve hotelwrc4 record5;
val updatewrc5 = update_reserve hotelwrc5 {id = 101, first_name = "B", last_name = "G", check_in_date= 1, num_of_nights = 5, num_of_occu = 2,
rm_config = DOUBLE_RM, num_of_gst = 1};
fun pred2 id (rrc:resrecord) = (id = (#id rrc));
in
if (filter pred2 101 (#resv_record updatewrc5)) = [{id = 101, first_name = "B", last_name = "G", check_in_date= 1, num_of_nights = 5, num_of_occu = 2,
rm_config = DOUBLE_RM, num_of_gst = 1}]
then print"\nTest of New Feature UpdateReserve succeed!\n\n"
else raise TestFailed
end
val tests = [testCreateSys, testReserve, Demo_lack_inventory, Demo_restriction, testCancel, queryInventory, Demo_cmplt, Demo_gstQtt,testUpdateReserve];
fun unitTest() = map (fn x => x()) tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment