OCaml matching in recursive function
Been exploring ocaml recently and was trying to implement a very basic REPL using recursive functions.
The usual REPL code we write are as below
loop do # ...end
Though in OCaml we usually don’t write imperative code, so trying that with functions would look like
let rec program_loop () = let _ = print_endline "Input proper input" in let input = read_line () in match input with | "add" -> print_endline "Input is add" | "print" -> print_endline "Input is print" | _ -> print_endline "Invalid input"; program_loop ()
This code looks pretty intuitive until we look at the match
here, there is a bug here. Formatting this snippet we will get the below
let rec program_loop () = let _ = print_endline "Input proper input" in let input = read_line () in match input with | "add" -> print_endline "Input is add" | "print" -> print_endline "Input is print" | _ -> (print_endline "Invalid input"); program_loop ())
We can see that the program_loop()
invocation has gone to the last catch of match. The semicolon does not help here as expected.
To make this work what we need to do is
let rec program_loop () = let _ = print_endline "Input proper input" in let input = read_line () in (match input with | "add" -> print_endline "Input is add" | "print" -> print_endline "Input is print" | _ -> print_endline "Invalid input"); program_loop ()
This is one of the gotchas of match in OCaml. Took me sometime to figure this and had help from the community as well. For a beginner this can be trippy.
The final snippet that I implemented is as below. It’s a simple program which runs and keeps taking input and give results. It’s self expalanatory so I will leave it to the reader to figure out the rest 😄
(* program.ml *)let print_and_return_list list = let _ = print_endline "List:: " in (match list with | [] -> print_endline "List is empty" | _ -> List.iter (fun x -> print_endline x) list); list
let parse_input input list = let parts = String.split_on_char ' ' input in match parts with | ["a"; v] -> v :: list | ["p"] -> print_and_return_list list | ["q"] -> exit 0 | _ -> (print_endline "Invalid input"; list)
let print_prompt () = Printf.printf ">> "
let rec program_loop master_list = let _ = print_prompt () in let input = read_line () in let new_list = parse_input input master_list in program_loop new_list
(* Call the loop function to start the program *)let _ = print_endline "Welcome to a POC REPL"let _ = program_loop []
Very clean and concise.
Updated on