src/main/java/org/organicdesign/fp/xform/Xform.java
@Override public <G,B> Or<G,B> foldUntil(G accum,
                                             Fn2<? super G,? super A,B> terminator,
                                             Fn2<? super G,? super A,G> reducer) {
        if (terminator == null) {
            return Or.good(fold(accum, reducer));
        }
        if (reducer == null) {
            throw new IllegalArgumentException("Can't fold with a null reduction function.");
        }

        // Yes, this is a cheap plastic imitation of what you'd hope for if you really need this
        // method.  The trouble is that when I implemented it correctly in _fold, I found
        // it was going to be incredibly difficult, or more likely impossible to implement
        // when the previous operation was flatMap, since you don't have the right result type to
        // check against when you recurse in to the flat mapping function, and if you check the
        // return from the recursion, it may have too many elements already.
        // In XformTest.java, there's something marked "Early termination test" that illustrates
        // this exact problem.
        List<A> as = this.toMutableList();
        for (A a : as) {
            B term = terminator.apply(accum, a);
            if (term != null) {
                return Or.bad(term);
            }
            accum = reducer.apply(accum, a);
        }
        return Or.good(accum);
    }
@Override public <G,B> Or<G,B> foldUntil(G accum,
                                             Fn2<? super G,? super A,B> terminator,
                                             Fn2<? super G,? super A,G> reducer) {
        if (terminator == null) {
            return Or.good(fold(accum, reducer));
        }
        if (reducer == null) {
            throw new IllegalArgumentException("Can't fold with a null reduction function.");
        }

        // Yes, this is a cheap plastic imitation of what you'd hope for if you really need this
        // method.  The trouble is that when I implemented it correctly in _fold, I found
        // it was going to be incredibly difficult, or more likely impossible to implement
        // when the previous operation was flatMap, since you don't have the right result type to
        // check against when you recurse in to the flat mapping function, and if you check the
        // return from the recursion, it may have too many elements already.
        // In XformTest.java, there's something marked "Early termination test" that illustrates
        // this exact problem.
        List<A> as = this.toMutableList();
        for (A a : as) {
            B term = terminator.apply(accum, a);
            if (term != null) {
                return Or.bad(term);
            }
            accum = reducer.apply(accum, a);
        }
        return Or.good(accum);
    }
@ Override public < G , B > Or < G , B > foldUntil ( G accum , Fn2 < ? super G , ? super A , B > terminator , Fn2 < ? super G , ? super A , G > reducer ) { if ( terminator == null ) { return Or . good ( fold ( accum , reducer ) ) ; } if ( reducer == null ) { throw new IllegalArgumentException ( "Can't fold with a null reduction function." ) ; } // Yes, this is a cheap plastic imitation of what you'd hope for if you really need this // method.  The trouble is that when I implemented it correctly in _fold, I found // it was going to be incredibly difficult, or more likely impossible to implement // when the previous operation was flatMap, since you don't have the right result type to // check against when you recurse in to the flat mapping function, and if you check the // return from the recursion, it may have too many elements already. // In XformTest.java, there's something marked "Early termination test" that illustrates // this exact problem. List < A > as = this . toMutableList ( ) ; for ( A a : as ) { B term = terminator . apply ( accum , a ) ; if ( term != null ) { return Or . bad ( term ) ; } accum = reducer . apply ( accum , a ) ; } return Or . good ( accum ) ; }
Thit implementation should be correct, but could be slow in the case where previous operations
are slow and the terminateWhen operation is fast and terminates early.  It actually renders
items to a mutable List, then runs through the list performing the requested reduction,
checking for early termination on the result.  If you can to a takeWhile() or take() earlier
in the transform chain instead of doing it here, always do that.  If you really need early
termination based on the *result* of a fold, and the operations are expensive or the input
is huge, try using a View instead.  If you don't care about those things, then this method is
perfect for you.

{@inheritDoc}
Thit implementation should be correct but could be slow in the case where previous operations are slow and the terminateWhen operation is fast and terminates early . It actually renders items to a mutable List then runs through the list performing the requested reduction checking for early termination on the result . If you can to a takeWhile () or take () earlier in the transform chain instead of doing it here always do that . If you really need early termination based on the * result * of a fold and the operations are expensive or the input is huge try using a View instead . If you don t care about those things then this method is perfect for you .