20-CS-4003-001 Organization of Programming Languages Fall 2017
Streams

Lambda calculus, Type theory, Formal semantics, Program analysis

All lectures
Non-blocking Streams

Instructions for all applets:
All applets contain a 'Next' button. Click it repeatedly.


    1.   stream_1.java



  -   A Stream class contains a first object, which in many of these examples is a BigInteger for easy comparisons, and a procedure rest() which returns the rest of the stream. There is also a field called isNull which returns true if the stream has no elements and false otherwise. A subclass of Stream needs to be designed with a constructor that installs the object representing the beginning of the stream into first. Information for doing this usually comes from the constructor's arguments. The procedure rest() needs to be designed to return a new object of the subclass with constructor arguments that will cause the first field of the new object to contain the next stream object. In this way, the delay-force paradigm of Scheme may be implemented: the delay is due to the creation of the new stream object being placed inside a procedure (rest) and the force happens when that procedure is invoked.

An example of a subclass of Stream that provides an infinite stream of BigIntegers is the Successor class. The rest procedure returns a new Successor object with a first value that is one greater than its own first value. Hence, successive stream elements are the integers beginning from the value given to the first creation of a Successor object. In this example a Successor stream is created (with first element 1) and assigned to the variable s.

 
    2.   stream_2.java



  -   A second stream, called Times, is introduced and connects with a Successor stream. Its purpose is to multiply all numbers in the Successor stream by a value that is given to its constructor. In this example, the connection of a Times stream that multiplies by 3 to a Successor stream and becomes the stream s.
 
    3.   stream_3.java


  -   A third stream, called Merge, is introduced and connects with a two multiplied Successor streams. Its purpose is to merge all numbers of two increasing sequences, as streams, into a single increasing sequence, as a stream. In this example, a Merge object connects to a stream produced by a Times object that multiplies numbers from a Successor stream by 3 and a Times object that multiplies numbers from another Successor stream by 5.
 
    4.   stream_4.java

StreamC.java
BIArrayC.java
Hamming_1.java

Brute.java

  -   Problem:
  Given: Set P of distinct primes.
  Produce: Distinct set of integers whose prime factors are in P.

Example: For P = {3,5,11}

Solution: 3,5,9,11,15,25,27,33,45,55,75,81,99,121,125,135 ...

Possible Program:
 For all numbers 1,2,3 ... do the following:
  If the number has only prime factors in P, print it.

This is unfortunately too slow to be of value. Run Brute.java to the left to see just how slow.

Better Program

        _  5, 11, 25, 55, 121, 125, ...
       /
      /	  
   3 <
      \ 
       \_  9, 15, 27, 33, 45, 75, 81, 99, 135, ...
           3 * {3, 5, 9, 11, 15, 25, 27, 33, 45, ...}
So, generalizing:  Hamming(P) =
  if P is empty then return nothing.
   return
  First(P)
   +
  Merge(First(P)*Hamming(P), Hamming(Rest(P))).

Search space, prime list = 3,5,11:


                               (3)
                            1*{3,5,11}
              _______________/     \_______________
             /                                     \
           (5)                                     (9)
        1*{5,11}                                3*{3,5,11}
    _____/    \____                       _______/     \_____
   /               \                     /                   \
 (11)              (25)                (15)                  (27)
1*{11}           5*{5,11}            3*{5,11}             9*{3,5,11}
    \           __/   \__           __/   \__             __/   \__
     \         /         \         /         \           /         \
    (121)    (55)      (125)     (33)       (75)       (45)       (81)
   11*{11}  5*{11}   25*{5,11}  3*{11}    15*{5,11}  9*{5,11}  27*{3,5,11}
        \       \      /   \        \       /   \     /   \      /   \
         ..      ..  ..     ..       ..   ..     .. ..     ..  ..     ..

The class Hamming provides a stream solution to this problem. It makes use of the Times and Merge classes of previous slides.

 
    5.   stream_5.java


  -   The class Remove filters objects from a stream. In this case only the number 15 is filtered.
 
    6.   stream_6.java


  -   The class Fibonacci computes a stream of Fibonacci numbers.
 
    7.   stream_7.java

graphical description

  -   The class Node to the left computes a topological sort of a given partial order of elements. Comments are in blue because there are many of them. The definition of Stream has changed slightly to allow any object to be a member of a stream. This example is rather deep because the number of procedures through with a token must travel to reach the point of demand could be huge. In additon, the rest() procedure is the most complex in this series. The red lines on the left show where the output stream is referenced by s. Walking through s is done as in the previous slide.