20 Intermediate Haskell Exercises

September 18th, 2008
class Fluffy f where
  furry :: (a -> b) -> f a -> f b
 
-- Exercise 1
-- Relative Difficulty: 1
instance Fluffy [] where
  furry = error "todo"
 
-- Exercise 2
-- Relative Difficulty: 1
instance Fluffy Maybe where
  furry = error "todo"
 
-- Exercise 3
-- Relative Difficulty: 5
instance Fluffy ((->) t) where
  furry = error "todo"
 
newtype EitherLeft b a = EitherLeft (Either a b)
newtype EitherRight a b = EitherRight (Either a b)
 
-- Exercise 4
-- Relative Difficulty: 5
instance Fluffy (EitherLeft t) where
  furry = error "todo"
 
-- Exercise 5
-- Relative Difficulty: 5
instance Fluffy (EitherRight t) where
  furry = error "todo"
 
class Misty m where
  banana :: (a -> m b) -> m a -> m b
  unicorn :: a -> m a
  -- Exercise 6
  -- Relative Difficulty: 3
  -- (use banana and/or unicorn)
  furry' :: (a -> b) -> m a -> m b
  furry' = error "todo"
 
-- Exercise 7
-- Relative Difficulty: 2
instance Misty [] where
  banana = error "todo"
  unicorn = error "todo"
 
-- Exercise 8
-- Relative Difficulty: 2
instance Misty Maybe where
  banana = error "todo"
  unicorn = error "todo"
 
-- Exercise 9
-- Relative Difficulty: 6
instance Misty ((->) t) where
  banana = error "todo"
  unicorn = error "todo"
 
-- Exercise 10
-- Relative Difficulty: 6
instance Misty (EitherLeft t) where
  banana = error "todo"
  unicorn = error "todo"
 
-- Exercise 11
-- Relative Difficulty: 6
instance Misty (EitherRight t) where
  banana = error "todo"
  unicorn = error "todo"
 
-- Exercise 12
-- Relative Difficulty: 3
jellybean :: (Misty m) => m (m a) -> m a
jellybean = error "todo"
 
-- Exercise 13
-- Relative Difficulty: 6
apple :: (Misty m) => m a -> m (a -> b) -> m b
apple = error "todo"
 
-- Exercise 14
-- Relative Difficulty: 6
moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]
moppy = error "todo"
 
-- Exercise 15
-- Relative Difficulty: 6
-- (bonus: use moppy)
sausage :: (Misty m) => [m a] -> m [a]
sausage = error "todo"
 
-- Exercise 16
-- Relative Difficulty: 6
-- (bonus: use apple + furry')
banana2 :: (Misty m) => (a -> b -> c) -> m a -> m b -> m c
banana2 = error "todo"
 
-- Exercise 17
-- Relative Difficulty: 6
-- (bonus: use apple + banana2)
banana3 :: (Misty m) => (a -> b -> c -> d) -> m a -> m b -> m c -> m d
banana3 = error "todo"
 
-- Exercise 18
-- Relative Difficulty: 6
-- (bonus: use apple + banana3)
banana4 :: (Misty m) => (a -> b -> c -> d -> e) -> m a -> m b -> m c -> m d -> m e
banana4 = error "todo"
 
newtype State s a = State {
  state :: (s -> (s, a))
}
 
-- Exercise 19
-- Relative Difficulty: 9
instance Fluffy (State s) where
  furry = error "todo"
 
-- Exercise 20
-- Relative Difficulty: 10
instance Misty (State s) where
  banana = error "todo"
  unicorn = error "todo"

Amuse yourself

September 11th, 2008

From “Never again will I doom the earth because of man…” By: God By J.D. Longstreet.

The argument goes something like this. Man cannot destroy the world, since Genesis 8:21 says so. Therefore, Global Warming is a conspiracy by scientific illiterates. Yes I cringed in embarrassment too.

Ignoring the scary implications of the prevalence of this kind of superstitious crackpottery, consider the somewhat amusing (I thought so anyway) excerpt below:

Then they [the Global Warming conspirators] use the guilt trip they have imposed on fellow human beings to shame us into completely altering the way we live. It is the oldest con game in the book. And the peoples of the planet are falling for it.

I wonder which book that might be :)

20 Intermediate Scala Exercises

September 10th, 2008

I will be publishing answers to these exercises as well as the Revised Scala Exercises in the near future. In the meantime, see if you can tackle the exercises below. In almost all cases, the type signature is enough to derive what the implementation should be. In all other cases, the solution is as difficult to derive anyway, so consider it an equivalent achievement.

The source file below compiles, but is missing certain function implementations (where you see error("todo")). Enjoy and if you have questions, please feel free to post them :)

trait PartialType[T[_, _], A] {
  type Apply[B] = T[A, B]
  type Flip[B] = T[B, A]
}
 
trait Fluffy[F[_]] {
  def furry[A, B](f: A => B, fa: F[A]): F[B]
}
 
object Fluffy {
  // Exercise 1
  // Relative Difficulty: 1
  def ListFluffy: Fluffy[List] = error("todo")
 
  // Exercise 2
  // Relative Difficulty: 1
  def OptionFluffy: Fluffy[Option] = error("todo")
 
  // Exercise 3
  // Relative Difficulty: 1
  def StreamFluffy: Fluffy[Stream] = error("todo")
 
  // Exercise 4
  // Relative Difficulty: 1
  def ArrayFluffy: Fluffy[Array] = error("todo")
 
  // Exercise 5
  // Relative Difficulty: 5
  def Function1Fluffy[X]: Fluffy[PartialType[Function1, X]#Apply] =
    error("todo")
 
  // Exercise 6
  // Relative Difficulty: 6
  def EitherLeftFluffy[X]: Fluffy[PartialType[Either.LeftProjection, X]#Flip] =
    error("todo")
 
  // Exercise 7
  // Relative Difficulty: 4
  def EitherRightFluffy[X]: Fluffy[PartialType[Either.RightProjection, X]#Apply] =
    error("todo")
}
 
trait Misty[M[_]] extends Fluffy[M] {
  def banana[A, B](f: A => M[B], ma: M[A]): M[B]
 
  def unicorn[A](a: A): M[A]
 
  // Exercise 8
  // Relative Difficulty: 3
  // (use banana and/or unicorn)
  def furry[A, B](f: A => B, ma: M[A]) = error("todo")
}
 
object Misty {
  // Exercise 9
  // Relative Difficulty: 2
  def ListMisty: Misty[List] = error("todo")
 
  // Exercise 10
  // Relative Difficulty: 2
  def OptionMisty: Misty[Option] = error("todo")
 
  // Exercise 11
  // Relative Difficulty: 2
  def StreamMisty: Misty[Stream] = error("todo")
 
  // Exercise 12
  // Relative Difficulty: 2
  def ArrayMisty: Misty[Array] = error("todo")
 
  // Exercise 13
  // Relative Difficulty: 6
  def Function1Misty[X]: Misty[PartialType[Function1, X]#Apply] =
    error("todo")
 
  // Exercise 14
  // Relative Difficulty: 7
  def EitherLeftMisty[X]: Misty[PartialType[Either.LeftProjection, X]#Flip] =
    error("todo")
 
  // Exercise 15
  // Relative Difficulty: 5
  def EitherRightMisty[X]: Misty[PartialType[Either.RightProjection, X]#Apply] =
    error("todo")
 
  // Exercise 16
  // Relative Difficulty: 3
  def jellybean[M[_], A](ma: M[M[A]], m: Misty[M]): M[A] = error("todo")
 
  // Exercise 17
  // Relative Difficulty: 6
  def apple[M[_], A, B](ma: M[A], mf: M[A => B], m: Misty[M]): M[B] =
    error("todo")
 
  // Exercise 18
  // Relative Difficulty: 6
  def moppy[M[_], A, B](as: List[A], f: A => M[B], m: Misty[M]): M[List[B]] =
    error("todo")
}
 
object AdvancedFun {
  case class State[S, A](f: S => (S, A))
 
  // Exercise 19
  // Relative Difficulty: 9
  def StateFluffy[S]: Fluffy[PartialType[State, S]#Apply] = error("todo")
 
  // Exercise 20
  // Relative Difficulty: 10
  def StateMisty[S]: Misty[PartialType[State, S]#Apply] = error("todo")
}

Haskell > Scala > (Java 7 <=> Functional Java) > Java

September 5th, 2008

Write a parser that accepts command line arguments.
For each command line argument, print out true or false,
depending on whether or not that value parses.

For a value to parse, it must consist entirely of these
characters: '(', ')', '[', ']‘. Any other character renders
the parse invalid and so prints “false”.

The value must also be “balanced”. That is, for each opening
parenthesis or bracket, it is matched by a closing parenthesis
or bracket accordingly. The different bracket types must not
intersperse.

Here are some examples of successfully parsing values that
result in printing “true”:

""
"()"
"[]"
"([])"
"[()]"
"[]()"
"[][[([])]]"

Here are some examples of values that fail the parsing and
result in printing “false”:

"("
")"
"["
"]"
"]["
")("
"( )"
"([)"
"[)]"
"([)]"
"({})"
"[())]"

Using Haskell (without Parsec):

import Prelude hiding (foldr, any)
import Control.Monad
import Data.Foldable
import System
 
tokens = [('(', ')'), ('[', ']')]
 
parse x = any null (foldr (\c f -> (\s -> (const (c:s)) `fmap`
            flip lookup ((uncurry (flip (,))) `fmap` tokens)  c `mplus`
              (flip lookup tokens c >>= (\v ->
                do h:t <- return s
                   guard (v == h)
                   return t))) =<< f) (return []) x)
 
main = getArgs >>= print . (parse `fmap`)

Using Scala (without scala.util.parsing):

object Parser {
  val tokens = List(('(', ')'), ('[', ']'))
 
  def parse(s: String) =
    s.foldRight[Option[String]](Some(""))((a, b) => b flatMap
      (ss => {
        val s = ss.toList
        (lookup(tokens map { case (x, y) => (y, x) }, a)
          map (t => (a::s)) orElse
        (lookup(tokens, a) flatMap (v => s match {
          case Nil => None
          case h :: t => if(v == h) Some(t) else None
        }))) map (_.mkString)
      })) exists (_.isEmpty)
 
  def main(args: Array[String]) {
    args foreach (parse _ andThen println)
  }
 
  // The Scala API needs hand-holding
  def lookup[A, B](x: List[(A, B)], a: A) =
    x.find { case (aa, _) => a == aa } map (_._2)
}

Using Java 1.5 and Functional Java:

import fj.F;
import fj.F2;
import fj.Function;
import static fj.P.p;
import fj.P1;
import fj.P2;
import fj.data.List;
import static fj.data.List.asString;
import static fj.data.List.fromString;
import static fj.data.List.list;
import static fj.data.List.lookup;
import fj.data.Option;
import static fj.data.Option.some;
import static fj.function.Strings.isEmpty;
import static fj.pre.Equal.charEqual;
import static fj.pre.Show.booleanShow;
 
final class Parser {
  @SuppressWarnings("unchecked")
  static final List<P2<Character, Character>> tokens =
    list(p('(', ')'), p('[', ']'));
 
  static boolean parse(final String s) {
    return fromString(s).foldRight(
      new F2<Character, Option<String>, Option<String>>() {
      public Option<String> f(final Character c, final Option<String> b) {
        return b.bind(new F<String, Option<String>>() {
          public Option<String> f(String s) {
            final List<Character> ss = fromString(s);
            return lookup(charEqual,
              tokens.map(P2.<Character, Character>swap_()), c)
                .map(Function.<Character,
                  List<Character>>constant(ss.cons(c)))
                .orElse(lookup(charEqual, tokens, c)
                .bind(new F<Character, Option<List<Character>>>() {
                  public Option<List<Character>> f(final Character v) {
                    return ss.isEmpty() || v != ss.head() ?
                        Option.<List<Character>>none() :
                        some(ss.tail());
                  }
                })).map(asString());
          }
        });
      }
    }, some("")).exists(isEmpty);
  }
 
  public static void main(final String[] args) {
    for(final String s : args) {
      booleanShow.println(parse(s));
    }
  }
}

Using Java BGGA and Functional Java:

import fj.Function;
import static fj.P.p;
import fj.P1;
import fj.P2;
import fj.data.List;
import static fj.data.List.asString;
import static fj.data.List.fromString;
import static fj.data.List.list;
import static fj.data.List.lookup;
import fj.data.Option;
import static fj.data.Option.some;
import static fj.function.Strings.isEmpty;
import static fj.pre.Equal.charEqual;
import static fj.pre.Show.booleanShow;
 
final class ParserBGGA {
  @SuppressWarnings("unchecked")
  static final List<P2<Character, Character>> tokens =
    list(p('(', ')'), p('[', ']'));
 
  static boolean parse(final String s) {
    return fromString(s).foldRight({ char c, Option<String> b =>
      b.bind({ String ss =>
        final List<Character> s = fromString(ss);
          lookup(charEqual,
            tokens.map(P2.<Character, Character>swap_()), c)
          .map(Function.<Character, List<Character>>constant(s.cons(c)))
          .orElse(lookup(charEqual, tokens, c)
          .bind({ char v =>
            s.isEmpty() || v != s.head() ?
              Option.<List<Character>>none() :
              some(s.tail())})).map(asString())})}
      , some("")).exists(isEmpty);
  }
 
  public static void main(final String[] args) {
    for(final String s : args) {
      booleanShow.println(parse(s));
    }
  }
}

A submission by a Java programmer who volunteered:

import java.util.ArrayList;
 
public class IsBalanced {
 
  private Stack stack = new Stack();
 
  public boolean isBalanced(String expression) {
 
    boolean isBalanced = true;
 
    for (int i = 0; i < expression.length(); i++) {
      char nextChar = expression.charAt(i);
 
      if (nextChar == '(') {
        stack.push('(');
      }
      else if (nextChar == '[') {
        stack.push('[');
      } else {
        if (!stack.isEmpty()) {
          char stackChar = (Character) stack.peek();
          if (nextChar == ')') {
            if (stackChar == '(') {
              stack.pop();
            } else {
              return false;
            }
 
          } else if (nextChar == ']') {
            if (stackChar == '[') {
              stack.pop();
            } else {
               return false;
            }
          }
        } else {
          return false;
        }
      }
    }
 
    if (!stack.isEmpty()) {
      isBalanced = false;
    }
    return isBalanced;
 
 
  }
 
  public static void main(String[] args) {
    System.out.println(args[0]);
    System.out.println((new IsBalanced()).isBalanced(args[0]));
  }
 
  private class Stack {
 
    private ArrayList stack = new ArrayList();
 
    public void push(char c) {
      stack.add(c);
 
    }
 
    public void pop() {
      stack.remove(stack.size()-1);
    }
 
 
    public Object peek() {
      return stack.get(stack.size()-1);
    }
 
    public boolean isEmpty() {
      return stack.size() == 0;
    }
  }
}

Forget the syntax for a moment and consider the compositional properties of each of these programs. For example, what if I were to add another pair of brackets such as '{' and '}'? Are there sub-programs that exist independently and can be extracted from the larger program? How does that affect my ability to reason (and therefore, read) the code?

What properties about the code make it easy to read?

Proving the existence of curry

September 5th, 2008

Prove ∀A. ∀B. ∀C. ((A∧B)→C)→A→B→C with a truth table.

WTF does that mean? It means that for any three propositions (A, B, C), then the conjunction (logical AND) of A and B implies C implies A implies B implies C. Note that → is right-associative, so X→Y→Z is the same as X→(Y→Z). If you are unfamiliar with denotational semantics (these crazy symbols), then perhaps this more relaxed notation makes sense forall A B C. ((A, B) -> C) -> A -> B -> C. Remember this notation, because we will use it later.

Here are some truth tables for conjunction and implication to get started:

Conjunction
P  Q  P∧Q
0  0  0
0  1  0
1  0  0
1  1  1

Implication
P  Q  P→Q
0  0  1
0  1  1
1  0  0
1  1  1

We can prove the truth of the above statement by observing a tautology (all true values) in a truth table.

1  2  3  4    5        6    7      8

A  B  C  A∧B  (A∧B)→C  B→C  A→B→C  ((A∧B)→C)→A→B→C
0  0  0  0    1        1    1      1
0  0  1  0    1        1    1      1
0  1  0  0    1        0    1      1
0  1  1  0    1        1    1      1
1  0  0  0    1        1    1      1
1  0  1  0    1        1    1      1
1  1  0  1    0        0    0      1
1  1  1  1    1        1    1      1

Observe that column 8 is true. Therefore ∀A. ∀B. ∀C. ((A∧B)→C)→A→B→C is a true statement.

Remember this statement earlier forall A B C. ((A, B) -> C) -> A -> B -> C? If you have GHCi installed, go to the prompt and type :set -fglasgow-exts. Then ask for the type of the curry function :type curry. You will see this:

Prelude> :type curry
curry :: forall a b c. ((a, b) -> c) -> a -> b -> c

Same same! :)

OK, so Haskell is for crazy people who use (oh dear!) logic which has nothing to do with that real world and they should all be writing enterprise Java applications like real programmers, right? Yeah right. Yep uh huh.

So let’s write this in Java, just for kicks and just to be noisy. Start with the conjunction and implication primitives:

interface Implication<P, Q> {
  Q implies(P p);
}
 
interface Conjunction<P, Q> {
  P p();
  Q q();
}

Next write the method for representing the aforementioned statement:

class S {
  static <A, B, C> Implication<Implication<Conjunction<A, B>, C>, Implication<A, Implication<B, C>>> s() {
    return null; // todo
  }
}

I shall leave it as a reader exercise to implement the s method. I assure you of only one possible implementation if you do not use null, exceptions or side-effects.

Function currying, like all programming concepts, is a logical statement under the Curry-Howard Isomorphism. Have a nice day :)

Sorry Ben

August 31st, 2008

Ben,
You have left two comments here, the second of which asked where your previous comment went. They were both caught by a spam filter and I am certain I pressed Approve on the first one and I definitely did on the second, but alas, they disappeared (WTF?).

Sorry about that, but if you could repost them, I will endeavour to ensure that they appear, since if I remember rightly, your original comment was a question of curiosity. Maybe the Wordpress guys can tell me why this is happening.

Flippin’ Scala

August 22nd, 2008

Once upon a time, I tried to write some Scala 2.7.1 for Functional Java and Reductio, but the compiler broke. So I filed the bug and waited for a fix. Thanks to Odersky et. al., the fix came promptly, so I started using one of the Scala 2.7.1->2.7.2 nightly builds and then I could compile my Scala code, yay! But that didn’t stop users complaining about crashes when using Scala 2.7.1 due its bad class file parser. Some users even stopped using Reductio because they don’t trust non-release builds. Oh well.

So I try out this new code snippet, nothing complicated:

class Foo[F[_]]
 
object Foo {
  def foo(n: Int)(implicit f: Foo[IN] forSome { type IN[_] }) = "foo"
 
  implicit val z: Foo[List] = new Foo[List]
 
  val t = foo(7)
}

But Scala 2.7.1 falls over. So does the 2.7.1->2.7.2 nightly build that I was using. Ugh! So I try out Scala 2.7.2-RC1, yay it compiles my legitimate source file. But does it compile all my other source?

Er no, Scala 2.7.2-RC1 produces bad class files when compiling code that is otherwise fine with previous Scala versions. In an attempt to obtain one bug fix I have also had to adopt another — one that makes its use non-viable. I am stuck with dealing with the former bug, which is also somewhat non-viable but only slightly more so than the latter. Give me a friggin’ break!

Ugh, this is not the first occurrence of this silliness. Flippin’ Scala, does this shit ever stop?

Introductory C-H and Static Typing

August 15th, 2008

We use logic every day. No, I don’t mean just us programmers; I mean all of us. Here is an observation about propositional logic:

I have three propositions P, Q and R.

It doesn’t matter what these three propositions actually are, it will always hold that, “if P then Q implies that if Q then R implies that if P then R”.

I’ve subverted that a little to try to make it read a little better, but perhaps look it at it a bit more formally:

forall P Q R. (P → Q) → (Q → R) → (P → R)

You might like to try it out on paper using some example propositions, such as:

  • P = Today is Tuesday
  • Q = I am going swimming
  • R = I have hairy armpits

I won’t bastardise it with English again ;) However, I will give you a hint. Here is the truth table for → (logical implication):

A | B | A → B
0 | 0 | 1
0 | 1 | 1
1 | 0 | 0
1 | 1 | 1

Here is where it gets a little interesting. This same logical statement forall P Q R. (P → Q) → (Q → R) → (P → R) can also be expressed in most programming languages. Here it is in Java as the z method:

interface F<A, B> { B f(A a); }
static <P, Q, R> F<P, R> z(F<P, Q> f, F<Q, R> g) { ...

It gets more interesting; there is only one implementation of this function if we assume a terminating subset of the language (for Java, no null or throwing an exception). If you add in a side-effect such as writing to a file or the network, then you have perverted the function signature. Java allows us to do that, so we also have to assume a subset of the language that disallows this unfortunate anomaly. This notion of a type signature having only one implementation is called once inhabited.

Let’s write out the truth table for this. Notice the consistent 1 values in the final column. The statement is a tautology.

P | Q | R | P → R | Q → R | P → R | (Q → R) → P → R | (P → Q) → (Q → R) → P → R
0 | 0 | 0 | 1     | 1     | 1     | 1               | 1
0 | 0 | 1 | 1     | 1     | 1     | 1               | 1
0 | 1 | 0 | 1     | 0     | 1     | 1               | 1
0 | 1 | 1 | 1     | 1     | 1     | 1               | 1
1 | 0 | 0 | 0     | 1     | 0     | 0               | 1
1 | 0 | 1 | 0     | 1     | 1     | 1               | 1
1 | 1 | 0 | 1     | 0     | 0     | 1               | 1
1 | 1 | 1 | 1     | 1     | 1     | 1               | 1

Under the Curry-Howard Isomorphism, logical implication is represented by a function or in the example above using Java, by the F interface. The z function is called function composition. It takes the two give functions/propositions and composes them.

In Haskell, function composition is not called z as we called it with Java, but instead (.). That’s a full-stop character in parentheses. We can ask for the type of (.) in the GHC interpreter:

Prelude> :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

We might even call it by passing in function instances (similar to instances of the Java F interface):

Prelude> ((+1) . (*7)) 20
141
 
Prelude> (reverse . map Char.toUpper) "hello there"
"EREHT OLLEH"

You could do the same using Java, but it’s a little more verbose, so I’ll omit that ;)

Here is a simple quiz. If we suppose the same F interface earlier, how many implementations of this function are there:

static <A> F<A, A> t() { ...

What about this one?

static <A, B> F<A, B> u() { ...

Java interop errata

August 13th, 2008

There are a few possibilities for improvement on this Scala Swing Example.

  • Removed unnecessary semi-colons
  • Inlined import
  • Removed = in main declaration (strongly advised on functions returning Unit and especially more for main)
  • Removed a few unnecessary parentheses
import javax.swing._
import java.awt.event.{ActionEvent, ActionListener}
 
object HelloWorld extends JFrame("Hello Swing") {
  def showButtonMessage(msg: String)  =
    JOptionPane.showMessageDialog(null, String.format("""<html>Hello from <b>Scala</b>. Button %s pressed""", Array(msg)));
 
  def main(args: Array[String]) {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    val button = new JButton("Click Me")
    button.addActionListener((e:ActionEvent) => showButtonMessage(e.getActionCommand.toString))
    getContentPane add button
    pack
    setVisible(true)
  }
 
  implicit def actionPerformedWrapper(func: (ActionEvent) => Unit) = new ActionListener {
    def actionPerformed(e:ActionEvent) = func(e)
  }
}

Functional Java 2.9

August 5th, 2008

Patient: I have 6 potentially failing methods (a, b, c, d, e, f) and if one of those fails, I want to cease execution and return that failure, otherwise continue execution.

Doctor: What do they return if they succeed?

Patient: Nothing, they side-effect

Doctor: eek! OK, let’s see what we can do? What happens after you’ve completed this computation?

Patient: Well, it gets a bit hairier you see. Then I have 3 more potentially failing computations (g, h, i) and if any of those fail (or the original failed), then I also want to fail, however, I want to keep the errors in these last three computations.

Doctor: So let’s get this right, you perform all of the latter three computations regardless of their outcome and you only succeed if all nine computations succeed and you fail otherwise?

Patient: Yes, that’s right and…

Doctor: And for whatever silly reason, you’re using Java.

Patient: cowers; er yeah.

Doctor: Well, I’ve told you about that, haven’t I?

Patient: cowers more; yes you have but…

Doctor: So, if any of the first six computations fail, then you check the latter three for failures as well. These latter three are side-effecting, void return type, as well aren’t they?

Patient: Yes…

Doctor: If the first six succeed, you perform the latter three computations anyway, accumulating potential failures.

Patient: Right, exactly

Doctor: And just as an interesting observation, you will have at most, four errors and possibly none in the event of all nine succeeding.

Patient: Umm yeah, I hadn’t thought of it that way.

Doctor: smiles

  Validation<Throwable, Unit> a;
  Validation<Throwable, Unit> b;
  Validation<Throwable, Unit> c;
  Validation<Throwable, Unit> d;
  Validation<Throwable, Unit> e;
  Validation<Throwable, Unit> f;
  ////
  Validation<Throwable, Unit> g;
  Validation<Throwable, Unit> h;
  Validation<Throwable, Unit> i;
 
  Validation<Throwable, Unit> first() {
    return a.sequence(b).
            sequence(c).
            sequence(d).
            sequence(e).
            sequence(f);
  }
 
  Option<NonEmptyList<Throwable>> second() {
    return first().nel().accumulate(Semigroup.<Throwable>nonEmptyListSemigroup(),
            g.nel(),
            h.nel(),
            i.nel());
  }

Doctor: Now, this is the best that Java can do at solving this very popular request of yours, but come and see me when you’re ready to upgrade your tools…

Patient: Thanks Doc! I will!

Doctor: outward smile, inward scepticism; In the meantime, I will prescribe you with Functional Java 2.9 which is only going to work if you exercise at least some amount of intellectual discipline. You will need it for the solution above.

Doctor: On your way then.

Update: Functional Java 2.10 includes Validation.sequence.