Haskell: actual IO monad implementation, in different language?

Here is an example of how one could implement the IO monad in Java:

package so.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import static so.io.IOMonad.*;  
import static so.io.ConsoleIO.*;    

/**
 * This is a type containing no data -- corresponds to () in Haskell.
 */
class Unit {
    public final static Unit VALUE = new Unit(); 
}

/**
 * This type represents a function from A to R
 */
interface Function<A,R> {
    public R apply(A argument);
}

/**
 * This type represents an action, yielding type R
 */
interface IO<R> {
    /**
     * Warning! May have arbitrary side-effects!
     */
    R unsafePerformIO();
}

/**
 * This class, internally impure, provides pure interface for action sequencing (aka Monad)
 */
class IOMonad {
    static <T> IO<T> pure(final T value) {
        return new IO<T>() {
            @Override
            public T unsafePerformIO() {
                return value;
            }
        };
    }

    static <T> IO<T> join(final IO<IO<T>> action) {
        return new IO<T>(){
            @Override
            public T unsafePerformIO() {
                return action.unsafePerformIO().unsafePerformIO();
            }
        };
    }

    static <A,B> IO<B> fmap(final Function<A,B> func, final IO<A> action) {
        return new IO<B>(){
            @Override
            public B unsafePerformIO() {
                return func.apply(action.unsafePerformIO());
            }
        };
    }

    static <A,B> IO<B> bind(IO<A> action, Function<A, IO<B>> func) {
        return join(fmap(func, action));
    }
}

/**
 * This class, internally impure, provides pure interface for interaction with stdin and stdout
 */
class ConsoleIO {
    static IO<Unit> putStrLn(final String line) {
        return new IO<Unit>() {
            @Override
            public Unit unsafePerformIO() {
                System.out.println(line);
                return Unit.VALUE;
            }
        };
    };

    // Java does not have first-class functions, thus this:
    final static Function<String, IO<Unit>> putStrLn = new Function<String, IO<Unit>>() {
        @Override
        public IO<Unit> apply(String argument) {
            return putStrLn(argument);
        }
    };

    final static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

    static IO<String> getLine = new IO<String>() {
            @Override
            public String unsafePerformIO() {
                try {
                    return in.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };
}

/**
 * The program composed out of IO actions in a purely functional manner.
 */
class Main {

    /**
     * A variant of bind, which discards the bound value.
     */
    static IO<Unit> bind_(final IO<Unit> a, final IO<Unit> b) {
        return bind(a, new Function<Unit, IO<Unit>>(){
            @Override
            public IO<Unit> apply(Unit argument) {
                return b;
            }
        });
    }

    /**
     * The greeting action -- asks the user for his name and then prints a greeting
     */
    final static IO<Unit> greet = 
            bind_(putStrLn("Enter your name:"), 
            bind(getLine, new Function<String, IO<Unit>>(){
                @Override
                public IO<Unit> apply(String argument) {
                    return putStrLn("Hello, " + argument + "!");
                }
            }));

    /**
     * A simple echo action -- reads a line, prints it back
     */
    final static IO<Unit> echo = bind(getLine, putStrLn);

    /**
     * A function taking some action and producing the same action run repeatedly forever (modulo stack overflow :D)
     */
    static IO<Unit> loop(final IO<Unit> action) {
        return bind(action, new Function<Unit, IO<Unit>>(){
            @Override
            public IO<Unit> apply(Unit argument) {
                return loop(action);
            }
        });
    }

    /**
     * The action corresponding to the whole program
     */
    final static IO<Unit> main = bind_(greet, bind_(putStrLn("Entering the echo loop."),loop(echo)));
}

/**
 * The runtime system, doing impure stuff to actually run our program.
 */
public class RTS {
    public static void main(String[] args) {
        Main.main.unsafePerformIO();
    }
}

This is a runtime system implementing interface to the console I/O together with a small purely functional program which greets the user and then runs an echo loop.

One can't implement the unsafe part in Haskell because Haskell is purely functional language. It is always implemented with lower-level facilities.


If you want to understand the implementation of the IO monad, it's very well described in an award-winning paper by Phil Wadler and Simon Peyton Jones, who were the ones who figured out how to use monads to do input/output in a pure language. The paper is Imperative Functional Programming and is on both authors' web sites.


With Java 8 Lambdas, you can take the code from Rotsor's answer above, remove the Function class as Java 8 provides a FunctionalInterface with does the same thing and remove the anonymous class cruft to achieve cleaner looking code like so:

package so.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.function.Function;

import static so.io.IOMonad.*;
import static so.io.ConsoleIO.*;

/**
 * This is a type containing no data -- corresponds to () in Haskell.
 */
class Unit {

   // -- Unit$

   public final static Unit VALUE = new Unit();

   private Unit() {
   }

}

/** This type represents an action, yielding type R */
@FunctionalInterface
interface IO<R> {

   /** Warning! May have arbitrary side-effects! */
   R unsafePerformIO();

}

/**
 * This, internally impure, provides pure interface for action sequencing (aka
 * Monad)
 */
interface IOMonad {

   // -- IOMonad$

   static <T> IO<T> pure(final T value) {
      return () -> value;
   }

   static <T> IO<T> join(final IO<IO<T>> action) {
      return () -> action.unsafePerformIO().unsafePerformIO();
   }

   static <A, B> IO<B> fmap(final Function<A, B> func, final IO<A> action) {
      return () -> func.apply(action.unsafePerformIO());
   }

   static <A, B> IO<B> bind(IO<A> action, Function<A, IO<B>> func) {
      return join(fmap(func, action));
   }

}

/**
 * This, internally impure, provides pure interface for interaction with stdin
 * and stdout
 */
interface ConsoleIO {

   // -- ConsoleIO$

   static IO<Unit> putStrLn(final String line) {
      return () -> {
         System.out.println(line);
         return Unit.VALUE;
      };
   };

   final static Function<String, IO<Unit>> putStrLn = arg -> putStrLn(arg);

   final static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

   static IO<String> getLine = () -> {
      try {
         return in.readLine();
      }

      catch (IOException e) {
         throw new RuntimeException(e);
      }
   };

}

/** The program composed out of IO actions in a purely functional manner. */
interface Main {

   // -- Main$

   /** A variant of bind, which discards the bound value. */
   static IO<Unit> bind_(final IO<Unit> a, final IO<Unit> b) {
      return bind(a, arg -> b);
   }

   /**
    * The greeting action -- asks the user for his name and then prints 
    * greeting
    */
   final static IO<Unit> greet = bind_(putStrLn("Enter your name:"),
         bind(getLine, arg -> putStrLn("Hello, " + arg + "!")));

   /** A simple echo action -- reads a line, prints it back */
   final static IO<Unit> echo = bind(getLine, putStrLn);

   /**
    * A function taking some action and producing the same action run repeatedly
    * forever (modulo stack overflow :D)
    */
   static IO<Unit> loop(final IO<Unit> action) {
      return bind(action, arg -> loop(action));
   }

    /** The action corresponding to the whole program */
    final static IO<Unit> main = bind_(greet, bind_(putStrLn("Entering the echo loop."), loop(echo)));

}

/** The runtime system, doing impure stuff to actually run our program. */
public interface RTS {

    // -- RTS$

    public static void main(String[] args) {
       Main.main.unsafePerformIO();
    }

 }

Note that I also changed class-declared static methods to interface-declared static methods. Why? No particular reason, just that you can in Java 8.