Revisiting Maybe in Java

I posted the link to Maybe in Java to programming.reddit.com and waited a good… hour or so, before giving up and going to bed. Actually, I happened to lose interest in posting it and by-chance, noticed my web browser still hadn’t completed the request on the way to bed. Nevertheless, it seems my HTTP request managed to make it there and when I woke up the next morning, there were all sorts of comments floating around. A few in particular asking something along the lines of, “what exactly has been achieved?”.

I will answer this question with “I have pointed out to Java programmers the concept of a very basic algebraic data type and importantly, in their language”. No mathematics, no type theory, nothing that will scare away your average J2EE Joey Jumper. I have also made a subliminal point of “hey! there are languages that already do this, only better!”. In particular, I have not provided anything that you should all go out and start using on your next WebSphere-fronted, RDBMS-backed, one-trillion-gazillion LOC web application. It seems the following points were missed in my original writing:

  • Throwing an exception is one of our possible options for evaluation of a partial function in Java. Here are all our options available in Java: … Emulate continuation passing style (CPS)
  • data Maybe a = Just a | Nothing (the Haskell equivalent i.e. omitting instances)
  • I’ll let your imagination run wild with possibilities from here :)

To remedy this situation, I have added further to the original Maybe type which was intentionally left incomplete, and it is still not complete. I hope this will help those who haven’t made the leap to do so and those who have made the leap, to understand my objective in this writing.

public abstract class Maybe<T> {
  private Maybe() {
  }
 
  public abstract <Q> Q maybe(JustC<Q, T> jc, NothingC<Q> nc);
 
  public static abstract class Nothing<T> extends Maybe<T> {
    private Nothing() {
    }
  }
 
  public static abstract class Just<T> extends Maybe<T> {
    private Just() {
    }
 
    public abstract T just();
  }
 
  public static <R> Maybe<R> _just(final R r) {
    return new Just<R>() {
      @Override
      public R just() {
        return r;
      }
 
      @Override
      public <Q> Q maybe(final JustC<Q, R> jc, final NothingC<Q> nc) {
        return jc.c(r);
      }
    };
  }
 
  public static <R> Maybe<R> _nothing() {
    return new Nothing<R>() {
      @Override
      public <Q> Q maybe(final JustC<Q, R> jc, final NothingC<Q> nc) {
        return nc.c();
      }
    };
  }
}
 
public interface JustC<Q, R> {
  Q c(R r);
}
 
public interface NothingC<Q> {
  Q c();
}

Those of you familiar with the Visitor Design Pattern (or any other GoF design euphemism) will immediately recognise the modification - hence the title of the post :). Please feel free to replace identifiers with your preferred view of the world; continuation, quasi-continuation, visitor, whatever.

For those who insist on returning null or throwing an exception/error, or more so, insist on failing to recognise the distinction, I have yielded to your pressure:

public final class NullNothingC<T> implements NothingC<T> {
  public T c() {
    return null;
  }
}
 
public final class ErrorNothingC<T> implements NothingC<T> {
  public T c() {
    throw new Error();
  }
}

2 Responses to “Revisiting Maybe in Java”

  1. Ricky Clarkson Says:

    Again with the [] for generics..

    I think that you pass a NothingC[Q] to the maybe method instead of a Q directly to facilitate lazy evaluation. I went down this road with my functional stuff, and I found that I just didn’t need it. It’s simpler to be able to pass 5 to a method, rather than calling some wrapping, e.g., new NonNullNothingC[Integer](5).

    It is quite rare that I have a case where calculating that value is expensive. Of course, it happens, and that’s when I choose laziness, but I don’t have to force laziness on the rest of my code.

    I have a badly named interface, Returner, which is rather like your NothingC, and if I want laziness then I make the Function (Function is called JustC in your post) that I pass as the first parameter to accept (accept is called maybe in your post) return a Returner[Q] and make the second parameter a Returner[Q] also.

    This is quite rare, and usually indicates that I’m doing stuff with side-effects anyway, so I probably need a good old refactor.

    Implementing the Either type from Haskell is a nice exercise in Java too - again, done it already, although I called my accept method ‘visit’, stupidly..

    http://functionalpeas.googlecode.com/svn/trunk/src/fpeas/either/

  2. λ Tony&#8217;s blog λ &#187; Blog Archive &#187; Maybe Monad in Java Says:

    [...] As I have shown previously, the problem of partial function in Java is not easily solved. The solution of the Maybe algebraic data type, while definitely superior to existing options, is cumbersome to implement and requires some functions defined over the type (isJust, isNothing, etc.) in order to be complete. As some point out, there is a preference for continuation passing to prevent the need for a cast (even though this case would be hidden). This prompted me to provide a more complete solution - which is still only a subset of a complete solution. [...]

Leave a Reply