\( \newcommand\D{\mathrm{d}} \newcommand\E{\mathrm{e}} \newcommand\I{\mathrm{i}} \newcommand\bigOh{\mathcal{O}} \newcommand{\cat}[1]{\mathbf{#1}} \newcommand\curl{\vec{\nabla}\times} \newcommand{\CC}{\mathbb{C}} \newcommand{\NN}{\mathbb{N}} \newcommand{\QQ}{\mathbb{Q}} \newcommand{\RR}{\mathbb{R}} \newcommand{\ZZ}{\mathbb{Z}} \)
UP | HOME

IO Monad - SML

Table of Contents

1. Introduction

We can construct the IO Monad in Standard ML, which has been done in Gordon's PhD thesis. There the construction uses an abstract type:

infix 1 >> >>=
abstype 'a Job = JOB of unit -> 'a
with
    (* exec : 'a Job -> 'a *)
    fun exec (JOB f)  = f ()
    (* return : 'a -> 'a Job *)
    fun return x      = JOB (fn _ => x)
    (* (>>=) : 'a Job * ('a -> 'b Job) -> 'b Job *)
    fun (JOB f) >>= q = JOB (fn _ => exec (q (f ())))
    (* getStr : int -> TextIO.vector Job *)
    fun getStr n      = JOB (fn _ => TextIO.inputN(TextIO.stdIn, n))
    (* putStr : string -> unit Job *)
    fun putStr s      = JOB (fn _ => print s)
end

(* (>>) : 'a Job * 'b Job -> 'b Job *)
fun p >> q  =  p >>= (fn _ => q);

(* gettingLine : string -> string Job *)
fun gettingLine s =
    getStr 1 >>= (fn c => if c = "\n"
                          then return(s)
                          else gettingLine (s^c));

(* getLine : string Job *)
val getLine = gettingLine "";

val main : unit Job =
    putStr "First name: " >> getLine >>= (fn first =>
    putStr "Second name: " >> getLine >>= (fn second =>
    putStr ("Hello "^first^" "^second^"\n")));
(* exec main; *)

2. Using Modules

We can encode the IO Monad using SML's Module system. The signature for a Monad would be:

signature MONAD = sig
    type 'a m;
    val return : 'a -> 'a m;
    val bind : 'a m -> ('a -> 'b m) -> 'b m;
end;

The IO Monad requires a few more public-facing methods.

signature IO_MONAD =
sig
    include MONAD;
    val exec : 'a m -> 'a;
    val getStr : int -> TextIO.vector m;
    val putStr : string -> unit m;
end;

Observe we just switched the Job constructor to m. The implementation details are straightforward.

3. References

  • Andrew Gordon,
    "Functional Programming and Input/Output".
    Ph.D. Thesis, Cambridge, 1994; Eprint.
  • Simon Peyton Jones,
    "Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell".
    in Engineering theories of software construction, IOS Press, 2001; Eprint and pdf.
    • Discusses the IO monad using a "two tier" semantics, with process semantics for the IO part and some denotational semantics for a lazy lambda calculus.

Last Updated 2023-02-27 Mon 07:43.