/*

Haskell meets Java

Today, we will explore the relationship of Haskell to Java, and, in the process, translate code back and forth between the two languages. In so doing, we will explore the more imperative features of Haskell (you can actually mutate variables, after all) and the more functional features of Java (you can actually write a monad in Java).

Accordingly, this file is both a valid literate Haskell file and a valid Java file.

> module Java where
> import Control.Monad ( when, liftM, guard )
> import Data.IORef
> import Data.List     ( stripPrefix )
> import Data.Maybe    ( maybe, isJust )
> import Text.Read     ( readMaybe )
*/
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class Haskell
{
/*

Printing

Comparing a program as basic as printing “Hello, world!” is not terribly enlightening. Instead, we’ll start with a program that asks the user for a number and then prints out every number from 1 up to the provided number.

First in idiomatic Haskell:

> printNums1 :: IO ()
> printNums1 = do
>   putStr "How high should I count? "
>   answerStr <- getLine
>   case readMaybe answerStr of
>     Nothing  -> putStrLn "Invalid entry. Please type a number."
>     Just num -> mapM_ print [1..num]

And now, in idiomatic Java:

*/
  public static void printNums1()
  {
    Scanner in = new Scanner(System.in);

    System.out.print("How high should I count? ");
    int answer = in.nextInt();
    for(int i = 1; i <= answer; i++)
    {
      System.out.println(i);
    }

    in.close();
  }
/*

But, we can do better than that with a little error checking:

*/

  public static void printNums2()
  {
    Scanner in = new Scanner(System.in);

    System.out.print("How high should I count? ");
    if(in.hasNextInt())
    {
      int answer = in.nextInt();
      for(int i = 1; i <= answer; i++)
      {
        System.out.println(i);
      }
    }
    else
    {
      in.nextLine();
      System.out.println("Invalid entry. Please type a number.");
    }

    in.close();
  }

/*

Note how easy it was to forget the error checking in Java! And, in truth, this doesn’t really work. If we call printNum2() two times in succession, we’ll see why. The problem is that hasNextInt() doesn’t consume any input. So, we could either manually gobble up the input or use exceptions.

Instead of going down this road, though, let’s make the Java look more like the Haskell. The first step is to use Java’s Optional type (directly inspired by Haskell’s Maybe and OCaml’s option) to define a safe function to parse an integer:

*/

  // No typeclasses. We have to be specific to integers. :(
  public static Optional<Integer> readMaybe(String in)
  {
    try {
      return Optional.of(Integer.parseInt(in));
    } catch(NumberFormatException e) {
      return Optional.empty();
    }
  }

/*

The Integer.parseInt(String) function throws the NumberFormatException when a parse fails. So, we just catch this exception and return Optional.empty() in that case. This should work nicely.

Unfortunately, Java doesn’t provide a nice pattern-matching mechanism for its Optional type. But, it does provide this function:

void ifPresent(Consumer<? super T> consumer)

What’s Consumer, you ask?

@FunctionalInterface
public interface Consumer<T>
{
  void accept(T t);
  // ...
}

Consumer is one of Java 8’s new functional interfaces. A functional interface is an interface with (roughly) one method. (There are various arcane rules around methods whoch overlap those from Object and other silly exceptions to the “one method” rule.) A Consumer<T> is a function that consumes T and produces nothing in response. In other words,

type Consumer a = a -> IO ()
ifPresent :: Optional a -> (a -> IO ()) -> IO ()

Haskell achievement unlocked!: You understand something in Haskell more easily than the equivalent Java!

Note how the Haskell equivalent to Java’s Consumer involves the IO monad. That’s because everything in Java must involve the IO monad – you can print, browse the Internet, and launch the missiles from anywhere in a Java program.

You’ll see in the Java declaration for ifPresent, above, that there is a curious type ? super T, whereas the Haskell equivalent seems to use just plain old T in that spot. (The “spot” is the second appearance of a in the Haskell type of ifPresent.) This difference has to do with Java’s subtyping relation. Haskell has no subtyping, so Haskellers don’t have to worry about this. And so, going forward, as Haskellers, we won’t worry about it.

In our printNums example, though, we’ll need to take action even if the optional value isn’t present. Optional doesn’t provide the right combinator, so we’ll write it ourselves:

*/
  public static <A, B> B maybe ( B b
                               , Function<? super A, ? extends B> f
                               , Optional<A> optA )
  {
    if (optA.isPresent())
    {
      return f.apply(optA.get());
    }
    else
    {
      return b;
    }
  }
/*

Writing that function makes me cringe, because my compiler isn’t checking that I’ve done a isPresent() check before using get(). But oh well. Happily, Haskell’s standard library provides the same combinator, called maybe.

> printNums3 :: IO ()
> printNums3 = do
>   putStr "How high should I count? "
>   answerStr <- getLine
>   maybe (putStrLn "Invalid entry. Please type a number.")
>         (\num -> mapM_ (putStrLn . show) [1..num])
>         (readMaybe answerStr)

And now, the Java version:

  public static void printNums3()
  {
    Scanner in = new Scanner(System.in);

    System.out.print("How high should I count? ");
    String answerStr = in.nextLine();
    maybe( System.out.println("Invalid entry. Please type a number.")
         , num -> {
           for(int i = 1; i <= num; i++)
           {
             System.out.println(i);
           }
         }
         , readMaybeInteger(answerStr) );

    in.close();
  }

Alas, that doesn’t compile, because Java can’t abstract over void! Let’s look at the type variables used in maybe. The two pieces passed in both result in void, but the type variable B can’t be void in Java. Furthermore, Java is an eager language, meaning that parameters to functions are evaluated before the function calls. Given this fact, the call to System.out.println in the Nothing case will happen before we check whether we have Just or Nothing. This is all wrong. We need to modify our combinator slightly to take two functions, so we can control their evaluation better. The function for the Nothing case takes no arguments and returns nothing, a use-case captured in the Runnable interface:

*/
  public static <A> void maybe2 ( Runnable nothingCase, Consumer<A> justCase
                                , Optional<A> optA )
  {
    if(optA.isPresent())
    {
      justCase.accept(optA.get());
    }
    else
    {
      nothingCase.run();
    }
  }
/*

Now, we’re ready to finish the translation to Java:

*/
  public static void printNums3()
  {
    Scanner in = new Scanner(System.in);

    System.out.print("How high should I count? ");
    String answerStr = in.nextLine();
    maybe2( () -> System.out.println("Invalid entry. Please type a number.")
          , num -> {
            for (int i = 1; i <= num; i++)
            {
              System.out.println(i);
            }
          }
          , readMaybe(answerStr) );

    in.close();
  }
/*

What have we gained here? More compile-time checking. Through the use of readMaybe, we now explicitly model the possibility of failure. And, through the use of the carefully-engineered maybe2 combinator, we are sure to safely access the contents of the Optional. By consistently programming this way, our Java code will have fewer errors.

Yet, there is still a small improvement: that for loop is really ugly in the middle of otherwise-functional code. Let’s get rid of it.

*/
  public static void printNums4()
  {
    Scanner in = new Scanner(System.in);

    System.out.print("How high should I count? ");
    String answerStr = in.nextLine();
    maybe2( () -> System.out.println("Invalid entry. Please type a number.")
          , num -> IntStream.rangeClosed(1, num)
                            .forEach(System.out::println)
          , readMaybe(answerStr) );

    in.close();
  }
/*

Ah. That’s much better. :)

Note the use of a method reference System.out::println, which passes a defined function as a functional interface parameter.

Mutable variables in Haskell

The previous section iterated through a program, making a Java program more like Haskell. Now, we’ll take the opposite approach and make a Haskell program more like Java, exploring mutation in Haskell.

Let’s remind ourselves of the interesting bits of the idiomatic Java program:

    System.out.print("How high should I count? ");
    int answer = in.nextInt();
    for(int i = 1; i <= answer; i++)
    {
      System.out.println(i);
    }

To do this in Haskell, for-loop and all, we’ll need variable mutation. Haskell provides this facility in its IORefs, imported from Data.IORef. The key functions are

newIORef    :: a -> IO (IORef a)
readIORef   :: IORef a -> IO a
writeIORef  :: IORef a -> a -> IO ()
modifyIORef :: IORef a -> (a -> a) -> IO ()  -- more efficient than read+write

An IORef is just a mutable cell that can be read from and written to from within the IO monad. Using a monad is necessary because, for example, readIORef called on the same IORef may return different results at different times, depending on what’s in the mutable cell.

We can write a for-loop in Haskell, but it’s a little clunky. Let’s see a cleaner solution first, in terms of while, which is much simpler. First, of course, we need to write while!

> while :: IO Bool   -- the condition
>       -> IO ()     -- the body
>       -> IO ()
> while cond body = do
>   b <- cond
>   when b