1. 14
  1.  

  2. 3
    import java.util.stream.*;
    
    public class Triangle {
        public static String triangle(int rows) {
            return IntStream
                    .rangeClosed(1, rows)
                    .boxed()
                    .map((row) -> Stream.iterate(row % 2, (n) -> n == 0 ? 1 : 0)
                                        .map(Object::toString)
                                        .limit(row)
                                        .collect(Collectors.joining(" ")))
                    .collect(Collectors.joining("\n"));
        }
    
        public static void main(String[] args) {
            System.out.println(triangle(4));
        }
    }
    

    Yes, it looks much uglier than Haskell version, but constructs are almost the same.

    (I’m not arguing that you can avoid imperativeness in Java, you almost can’t, and even Streams are imperative but somewhat composable)

    1. 5

      to be fair, java 8 (and streams) had only been out in the wild for 5 months when this was written.

      1. 3

        But are those features of Java actually taught at university? Because they sure don’t spend time on them where I’m at.

        1. 2

          I haven’t run across it, though I could imagine some contexts where they might be. I might even consider doing it in the future, given the right circumstances. But I think they’re not that likely circumstances. Usually university courses are trying to teach at least two things with a programming language (or language construct): the language itself, and some broader principle, which students will hopefully retain long-term and be able to apply even when languages inevitably change over. So typically Java has been used either as “generic intro-level language” or “OO language”, which Java 8+ streams don’t fit that well into.

          In universities where Java’s used as the standard intro-level language, there’s some advantage to continuing to scaffold atop it for further things, because you can assume everyone already knows the basics. But it’s falling out of favor for intro-level classes in favor of Python. So I think you will either see people introducing this “streams” style of programming in Python if the circumstances fit, or else they’ll stick with a more traditional introduction to sequence filtering/mapping/etc. in the context of an introducion to functional programming, in Haskell or ML or maybe some Lisp dialect.

          1. 1

            So I think you will either see people introducing this “streams” style of programming in Python if the circumstances fit, or else they’ll stick with a more traditional introduction to sequence filtering/mapping/etc. in the context of an introducion to functional programming, in Haskell or ML or maybe some Lisp dialect.

            I’m aware of some libraries that provide special syntax for that in Python, but I don’t think anything other than list comprehensions (and maybe higher-order functions) for this kind of stuff is considered “Pythonic”.

      2. 3

        I did much the same but tried to introduce names in the same places as in the original; as relatively idiomatic Java that’s:

        public class Triangles {
            public static void main( String[] args ) {
                System.out.println( triangle( 4 ) );
            }
        
            public static String triangle( int n ) {
                return IntStream.rangeClosed( 1, n ).mapToObj( Triangles::line ).collect( Collectors.joining( "\n" ) );
            }
        
            public static String line( int n ) {
                return alternating( n ).limit( n ).mapToObj( Integer::toString ).collect( Collectors.joining( " " ) );
            }
        
            public static IntStream alternating( int start ) {
                return IntStream.iterate( start, i -> i + 1 ).map( i -> i % 2 );
            }
        }
        

        You can also go totally crazy, but I wouldn’t recommend it:

        public class Triangles {
            public static void main( String[] args ) {
                IntFunction<IntStream> alternating = i -> IntStream.iterate( i, n -> n + 1 ).map( n -> n % 2 );
                IntFunction<String> lines = l -> alternating.apply( l ).limit( l ).mapToObj( Integer::toString ).collect( Collectors.joining( " " ) );
                IntFunction<String> triangle = n -> IntStream.rangeClosed( 1, n ).mapToObj( Triangles::line ).collect( Collectors.joining( "\n" ) );
        
                System.out.println( triangle.apply( 4 ) );
            }
        }
        
        1. 2

          Great, now I want to my own version but I have to work…

          1. 5

            I wrote mine too! ;)

            Funny how similar Rust and Haskell are in those small examples.