Channel Directions in Standard ML

(* When using channels as function parameters in Standard ML, we can use
   ref types to simulate send-only or receive-only channels. This specificity
   increases the type-safety of the program. *)

(* This `ping` function only accepts a channel for sending values. *)
fun ping (pings: string option ref, msg: string) =
    pings := SOME msg

(* The `pong` function accepts one channel for receives (pings)
   and a second for sends (pongs). *)
fun pong (pings: string option ref, pongs: string option ref) =
    case !pings of
        SOME msg => pongs := SOME msg
      | NONE => ()

(* Main function to demonstrate the usage *)
fun main () =
    let
        val pings = ref NONE
        val pongs = ref NONE
    in
        ping (pings, "passed message");
        pong (pings, pongs);
        case !pongs of
            SOME msg => print (msg ^ "\n")
          | NONE => print "No message received\n"
    end

(* Run the main function *)
val _ = main ()

In Standard ML, we don’t have built-in channels like in some other languages. However, we can simulate similar behavior using reference types (ref) and options. Here’s how the code works:

  1. We define ping and pong functions that operate on string option ref types. These act as our “channels”.

  2. The ping function takes a “send-only” channel (pings) and a message. It updates the reference with the message.

  3. The pong function takes a “receive-only” channel (pings) and a “send-only” channel (pongs). It reads from pings and writes to pongs.

  4. In the main function, we create two references to simulate channels, then call ping and pong, and finally print the result.

To run this program, you would typically save it in a file (e.g., channel_directions.sml) and then use an SML interpreter or compiler. For example, with Standard ML of New Jersey (SML/NJ):

$ sml channel_directions.sml
passed message

This example demonstrates how to simulate channel-like behavior in Standard ML, even though the language doesn’t have built-in support for channels. The use of reference types and options allows us to create a similar send/receive paradigm.