type command = { name : string; args : string list } type context = { counter : int } type request = | Hello of string | GetCtx | Inc;; type response = | Hello of string | GetCtx of context | Inc;; let parse_cmd cmd_line : command = let cmd_split = String.split_on_char ' ' cmd_line in {name = List.hd cmd_split; args = List.tl cmd_split};; let print_cmd cmd : unit = Printf.printf "Command [%s]\n" cmd.name; List.iteri (Printf.printf "\tArg [%d] -> %s\n") cmd.args;; let print_ctx (ctx: context) : unit = Printf.printf "Context [counter] = %d\n" ctx.counter;; let request_of_cmd (cmd: command) : (request, string) result = match cmd.name with | "hello" -> Ok (Hello ("Hello, " ^ (String.concat "," cmd.args))) | "getctx" -> Ok (GetCtx) | "inc" -> Ok (Inc) | _ -> Error "Unkown command name";; let response_print (res: response) = match res with | Hello text -> print_endline text | GetCtx ctx -> print_ctx ctx | Inc -> print_endline "Incremented!";; let handle_request (ctx: context) (req: request) : context * response = match req with | Hello txt -> ctx, Hello txt | GetCtx -> (ctx, GetCtx ctx) | Inc -> { counter = ctx.counter + 1 }, Inc;; let parse_cmds cmd_strs : command list = List.map parse_cmd cmd_strs;; let rec print_cmds cmds : unit = match cmds with | [] -> () | h :: t -> print_cmd h; print_cmds t;; let handle_cmd (ctx: context) (cmd: command) : (context * response, string) result = let req = request_of_cmd cmd in match req with | Ok req -> Ok (handle_request ctx req) | Error err -> Error err;; let rec handle_cmds (init_ctx: context) (cmds: command list) : (context, string) result = match cmds with | [] -> Ok init_ctx | cmd :: rest -> (handle_cmds (match (handle_cmd init_ctx cmd) with | Ok (ctx, res) -> response_print res; ctx | Error (str) -> print_endline str; init_ctx)) rest;; let print_handle_result res = match res with | Ok ctx -> print_ctx ctx | Error err -> print_endline err;; let string_lpad (str: string) (pad: char) (width: int) : string = let rem = width - String.length str in let rec append_left (str: string) (pad: char) (count: int) : string = match count with | 0 -> str | n -> append_left ((String.make 1 pad) ^ str) pad (n - 1) in append_left str pad rem;; let string_rpad (str: string) (pad: char) (width: int) : string = let rem = width - String.length str in let rec append_right (str: string) (pad: char) (count: int) : string = match count with | 0 -> str | n -> append_right (str ^ (String.make 1 pad)) pad (n - 1) in append_right str pad rem;; let string_center (s: string) (pad: char) (width : int) : string = let str_len = String.length s in let side_pad = (width+str_len)/2 in string_rpad (string_lpad s pad side_pad) pad width;; let char_repeat (c: char) (times: int) : string = string_lpad "" c times;; let print_heading (s: string) : unit = print_endline (char_repeat '=' 64); print_endline (string_center (string_center s ' ' 32) '=' 64); print_endline (char_repeat '=' 64);; let get_init_ctx : context = { counter = 0 };; let cmds = parse_cmds [ "hello Maciek"; "getctx"; "inc"; "getctx"; "inc"; ];; print_heading "Command processing";; print_cmds cmds;; print_heading "Command handling";; let final_result = handle_cmds get_init_ctx cmds;; print_heading "Final result";; print_handle_result final_result