skip to content

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