Channel Directions in OCaml

OCaml doesn’t have built-in channels like Go, so we’ll use a similar concept with queues from the standard library. The idea of send-only and receive-only channels will be simulated using functions that only allow sending or receiving.

open Queue

(* This `ping` function only accepts a queue for sending
   values. It would be a type error to try to receive from
   this queue in this function. *)
let ping (pings : string Queue.t) (msg : string) : unit =
  Queue.add msg pings

(* The `pong` function accepts one queue for receives
   (`pings`) and a second for sends (`pongs`). *)
let pong (pings : string Queue.t) (pongs : string Queue.t) : unit =
  let msg = Queue.take pings in
  Queue.add msg pongs

let main () =
  let pings = Queue.create () in
  let pongs = Queue.create () in
  ping pings "passed message";
  pong pings pongs;
  Printf.printf "%s\n" (Queue.take pongs)

let () = main ()

When using queues as function parameters, we can specify if a queue is meant to only send or receive values by the operations we perform on it. This specificity increases the type-safety of the program.

To run the program, save it as channel_directions.ml and use the OCaml compiler:

$ ocamlc -o channel_directions channel_directions.ml
$ ./channel_directions
passed message

In this OCaml version:

  1. We use Queue.t from the standard library to simulate channels.
  2. The ping function only adds to the queue, simulating a send-only channel.
  3. The pong function takes from one queue and adds to another, simulating receive and send operations.
  4. In the main function, we create two queues, pass messages between them, and print the result.

This example demonstrates how OCaml’s type system can enforce similar constraints to Go’s channel directions, even though the underlying implementation is different.