Monadics { public static <A> IteratorMonadic<A> mlazy(final Iterator<A> as) { return new IteratorMonadic<A>() { @Override public <B> IteratorMonadic<B> fmap(final Function<A, B> f) { return mlazy(new Iter<B>() { @Override public boolean hasNext() { return as.hasNext(); } @Override public B next() { return f.apply(as.next()); } }); } @Override public <B> IteratorMonadic<B> mapIndex(final Function2<A, Integer, B> f) { return mlazy(new Iter<B>() { private int i = 0; @Override public boolean hasNext() { return as.hasNext(); } @Override public B next() { return f.apply(as.next(), i++); } }); } @Override public <B> IteratorMonadic<B> bind(final Function<A, Iterator<B>> f) { return mlazy(new Iter<B>() { @Override public boolean hasNext() { return step.hasNext() || step().hasNext(); } @Override public B next() { if (step.hasNext()) { return step.next(); } else { return step().next(); } } private Iterator<B> step = Monadics.emptyIter(); private Iterator<B> step() { while (!step.hasNext() && as.hasNext()) { step = f.apply(as.next()); } return step; } }); } @Override public boolean exists(Function<A, Boolean> p) { for (A a : forc(as)) { if (p.apply(a)) return true; } return false; } @Override public IteratorMonadic<A> filter(final Function<A, Boolean> p) { return mlazy(new Iter<A>() { private A next = null; @Override public boolean hasNext() { if (next != null) { return true; } else { for (A a : forc(as)) { if (p.apply(a)) { next = a; return true; } } return false; } } @Override public A next() { try { if (next != null || hasNext()) { return next; } else { throw new NoSuchElementException(); } } finally { next = null; } } }); } @Override public IteratorMonadic<A> take(final int n) { return mlazy(new Iter<A>() { private int count = 0; @Override public boolean hasNext() { return count < n && as.hasNext(); } @Override public A next() { if (count < n) { count++; return as.next(); } else { throw new NoSuchElementException(); } } }); } @Override public IteratorMonadic<A> each(final Function<A, Void> e) { return mlazy(new Iter<A>() { @Override public boolean hasNext() { return as.hasNext(); } @Override public A next() { final A a = as.next(); e.apply(a); return a; } }); } @Override public IteratorMonadic<A> eachIndex(final Function2<A, Integer, Void> e) { return mlazy(new Iter<A>() { private int i = 0; @Override public boolean hasNext() { return as.hasNext(); } @Override public A next() { final A a = as.next(); e.apply(a, i++); return a; } }); } @Override public Iterator<A> iterator() { return as; } @Override public Iterator<A> value() { return as; } @Override public List<A> eval() { return toList(as); } }; } private  Monadics(); static ListMonadic<A> mlist(final Collection<A> as); static ListMonadic<A> mlist(final List<A> as); static ListMonadic<A> mlist(final A... as); static ListMonadic<A> mlist(final Iterator<A> as); static IteratorMonadic<A> mlazy(final Iterator<A> as); static IteratorMonadic<A> mlazy(final List<A> as);  }
@Test public void testLazyMap() { final boolean[] applied = {false}; IteratorMonadic<Integer> im = mlazy(asList(1, 2, 3, 4, 5)) .map(new Function<Integer, Integer>() { @Override public Integer apply(Integer i) { applied[0] = true; return i * i; } }) .map(new Function<Integer, Integer>() { @Override public Integer apply(Integer i) { applied[0] = true; return i + i; } }); assertFalse(applied[0]); im.value(); assertFalse(applied[0]); List<Integer> eval = im.eval(); assertTrue(applied[0]); assertArrayEquals(new Integer[]{2, 8, 18, 32, 50}, eval.toArray(new Integer[]{})); assertTrue(Collections.toList( mlazy(Collections.<Integer>nil()).map(Functions.<Integer>identity()).value() ).isEmpty()); }
@Test public void testLazyMapIndex() { List<Integer> eval = mlazy(asList(1, 2, 3, 4, 5)).mapIndex(new Function2<Integer, Integer, Integer>() { @Override public Integer apply(Integer n, Integer i) { return n + i; } }).eval(); assertArrayEquals(new Integer[]{1, 3, 5, 7, 9}, eval.toArray(new Integer[]{})); }
@Test public void testLazyFlatMap() { List<Integer> eval = mlazy(asList(1, 2, 3)) .flatMap(new Function<Integer, Iterator<Integer>>() { @Override public Iterator<Integer> apply(Integer integer) { if (integer >= 2) { return asList(1, 2, 3).iterator(); } else { return java.util.Collections.<Integer>emptyList().iterator(); } } }) .flatMap(new Function<Integer, Iterator<Integer>>() { @Override public Iterator<Integer> apply(Integer integer) { return asList(integer * integer).iterator(); } }) .eval(); assertArrayEquals(array(1, 4, 9, 1, 4, 9), Collections.toArray(Integer.class, eval)); }
@Test public void testLazyFlatMap2() { List<Integer> eval = mlazy(asList(1, 2, 3)) .flatMap(new Function<Integer, Iterator<Integer>>() { @Override public Iterator<Integer> apply(Integer integer) { if (integer != 2) { return asList(1, 2, 3).iterator(); } else { return java.util.Collections.<Integer>emptyList().iterator(); } } }) .flatMap(new Function<Integer, Iterator<Integer>>() { @Override public Iterator<Integer> apply(Integer integer) { return asList(integer * integer).iterator(); } }) .eval(); assertArrayEquals(array(1, 4, 9, 1, 4, 9), Collections.toArray(Integer.class, eval)); }
@Test public void testLazyFlatMapDoubling() { List<Integer> eval = mlazy(asList(1, 2, 3, 4, 5)).flatMap(MonadicsTest.<Integer>twice()).eval(); assertArrayEquals(new Integer[]{1, 1, 2, 2, 3, 3, 4, 4, 5, 5}, eval.toArray(new Integer[]{})); }
@Test public void testLazyFlatMapKeepSize() { List<Integer> eval = mlazy(asList(1)) .flatMap(new Function<Integer, Iterator<Integer>>() { @Override public Iterator<Integer> apply(Integer integer) { return Option.<Integer>some(2).iterator(); } }) .eval(); assertArrayEquals(new Integer[]{2}, eval.toArray(new Integer[0])); }
@Test public void testLazyFlatMapTimes() { List<Integer> eval = mlazy(asList(1, 2, 3, 4)).flatMap(times).eval(); assertArrayEquals(new Integer[]{1, 2, 2, 3, 3, 3, 4, 4, 4, 4}, eval.toArray(new Integer[0])); }
@Test public void testLazyFlatMapEmptyInput() { assertTrue(mlazy(java.util.Collections.<Integer>emptyList()).flatMap(times).eval().isEmpty()); }
@Test public void testLazyFlatMapEmptyOutput() { List<Integer> eval = mlazy(asList(1, 2, 3)) .flatMap(new Function<Integer, Iterator<Integer>>() { @Override public Iterator<Integer> apply(Integer integer) { return Option.<Integer>none().iterator(); } }) .eval(); assertTrue(eval.isEmpty()); }
@Test public void testLazyFlatMapHasNext() { Iterator<Integer> ints = mlazy(asList(1, 2)).flatMap(MonadicsTest.<Integer>twice()).value(); assertTrue(ints.hasNext()); assertTrue(ints.hasNext()); assertTrue(ints.hasNext()); assertTrue(ints.hasNext()); assertTrue(ints.hasNext()); }
@Test public void testLazyFlatMapMultiple() { List<Integer> eval = mlazy(asList(1, 2)) .flatMap(MonadicsTest.<Integer>twice()) .flatMap(MonadicsTest.<Integer>twice()) .eval(); assertArrayEquals(new Integer[]{1, 1, 1, 1, 2, 2, 2, 2}, eval.toArray(new Integer[]{})); }
@Test public void testLazyEachEmpty() { final boolean[] run = {false}; mlazy(java.util.Collections.emptyList()) .each(new Effect<Object>() { @Override public void run(Object o) { run[0] = true; } }) .eval(); assertFalse(run[0]); }
@Test public void testLazyEach() { final int[] sum = {0}; mlazy(asList(1, 2, 3, 4, 5)) .each(new Effect<Integer>() { @Override public void run(Integer o) { sum[0] += o; } }) .eval(); assertEquals(15, sum[0]); }
@Test public void testLazyEachIndexEmpty() { final boolean[] run = {false}; mlazy(java.util.Collections.emptyList()) .eachIndex(new Effect2<Object, Integer>() { @Override public void run(Object o, Integer i) { run[0] = true; } }) .eval(); assertFalse(run[0]); }
@Test public void testLazyEachIndex() { final int[] sum = {0}; mlazy(asList(1, 2, 3, 4, 5)) .eachIndex(new Effect2<Integer, Integer>() { @Override public void run(Integer o, Integer i) { sum[0] += (o * i); } }) .eval(); assertEquals(40, sum[0]); }
@Test public void testLazyTake() { assertTrue(mlazy(asList(1, 2, 3, 4, 5)).take(0).eval().isEmpty()); assertEquals(3, mlazy(asList(1, 2, 3, 4, 5)).take(3).eval().size()); assertEquals(5, mlazy(asList(1, 2, 3, 4, 5)).take(5).eval().size()); assertEquals(5, mlazy(asList(1, 2, 3, 4, 5)).take(10).eval().size()); assertEquals(100, mlazy(constant(10)).take(100).eval().size()); }
@Test public void testLazyFilter() { assertEquals(5, mlazy(intRangeE(0, 10)).filter(Booleans.lt(5)).eval().size()); assertEquals(10, mlazy(intRangeE(0, 10)).filter(Booleans.lt(100)).eval().size()); assertEquals(0, mlazy(intRangeE(0, 10)).filter(Booleans.lt(0)).eval().size()); }
@Test public void testLazyExists() { assertTrue(mlazy(intRangeE(0, 10)).exists(Booleans.gt(5))); assertFalse(mlazy(intRangeE(0, 10)).exists(Booleans.gt(9))); }