Showing posts with label stream. Show all posts
Showing posts with label stream. Show all posts

Thursday, March 4, 2010

Zip with a constant value

A simple tip for zipping a List (or other collection) with a single value.

  1. scala> Stream.continually("h") zip List(1,2,3,4)
  2. res2: scala.collection.immutable.Stream[(java.lang.String, Int)] = Stream((h,1), ?)
  3. scala> res2 mkString ","
  4. res3: String = (h,1),(h,2),(h,3),(h,4)
  5. scala> List(1,2,3,4) zip Stream.continually("h")
  6. res4: List[(Int, java.lang.String)] = List((1,h), (2,h), (3,h), (4,h))

Friday, January 22, 2010

Streams 2: Stream construction

This post just adds to the information about streams in the previous post Introducing Streams. In this topic the methods in the Stream object are looked at a little closer:
(standard warning. Examples were done in Scala 2.8 so some examples may need to be modified for Scala 2.7)
  1. scala> import Stream._
  2. import Stream._
  3. // the empty stream.  good for terminating a stream
  4. scala> empty        
  5. res0: scala.collection.immutable.Stream[Nothing] = Stream()
  6. // one way to declare a stream. 
  7. scala> 1 #:: 2 #:: empty foreach (println _)
  8. 1
  9. 2
  10.  // the other main way to create a stream
  11. scala> cons(1, cons(2, empty)) foreach println
  12. 1
  13. 2
  14. /*
  15. Neither of the previous methods of stream creation are particularily useful because they are explicit and therefore they may as well be Lists or some other collection.  There is very little benefit in those cases.  However when the cons of a stream (tail) is defined as a function then things get a bit more interesting
  16. */
  17. scala> def i(x:Int,y:Int):Stream[Int] = (x*y) #:: i(x+1,y*2)
  18. i: (x: Int,y: Int)Stream[Int]
  19. scala> i(2,3) take 3 foreach println
  20. 6
  21. 18
  22. 48
  23. // now lets visit a few more methods in the Stream object
  24. // create an infinite stream starting at 10
  25. scala> from (10) take 3 foreach println     
  26. 10
  27. 11
  28. 12
  29. // an infinite stream starting at 10 an increasing by 3
  30. scala> from (10,3) take 3 foreach println
  31. 10
  32. 13
  33. 16
  34. // converting an interator to a stream
  35. scala> (1 until 4).iterator.toStream foreach println
  36. 1
  37. 2
  38. 3
  39. // creating an Iterable to a stream
  40. scala> (1 until 4).toStream foreach println         
  41. 1
  42. 2
  43. 3
  44. // a stream that always returns 7
  45. // the following is a pretty convoluted way to compute 7*49 :-P
  46. scala> continually(7) take 49 reduceLeft {_ + _}
  47. res10: Int = 343
  48. // create a stream of 6 streams
  49. scala> fill(6)(1 to 2 toStream) foreach println
  50. Stream(1, ?)
  51. Stream(1, ?)
  52. Stream(1, ?)
  53. Stream(1, ?)
  54. Stream(1, ?)
  55. Stream(1, ?)
  56. /*
  57. create the same stream as the last example but flatten it out so instead of being a stream of 6 streams it is a stream of 12 elements. Each element in each of the streams are visited in order
  58. */
  59. scala> fill(6)(1 to 2 toStream).flatten take 6 foreach println
  60. 1
  61. 2
  62. 1
  63. 2
  64. 1
  65. 2
  66. /*
  67. equivalent to:
  68. (1 until 20 by 3).toStream foreach println
  69. */
  70. scala> range(1, 20, 3) foreach println
  71. 1
  72. 4
  73. 7
  74. 10
  75. 13
  76. 16
  77. 19
  78. /*
  79. equivalent to
  80. (1 until 3).toStream foreach println
  81. */
  82. scala> range(1,3) foreach println          
  83. 1
  84. 2
  85. /*
  86. iterate is fun! 
  87. signature is iterator(start)(elem)
  88. basically starting at 3 execute the function on the previous value in the stream.
  89. This is an infinite stream
  90. */
  91. scala> iterate(3){i => i-10} take 5 foreach println _               
  92. 3
  93. -7
  94. -17
  95. -27
  96. -37
  97. /*
  98. Another example
  99. */
  100. scala> iterate(3){i => i*2} take 5 foreach println _ 
  101. 3
  102. 6
  103. 12
  104. 24
  105. 48
  106. /*
  107. A final example
  108. */
  109. scala> iterate(3){i => i} take 5 foreach println _  
  110. 3
  111. 3
  112. 3
  113. 3
  114. 3
  115. /*
  116. The real final,final example.  This example uses the optional length parameter.   So the stream is restricted to 5 elements
  117. */
  118. scala> iterate(3,5){i => i} foreach println       
  119. 3
  120. 3
  121. 3
  122. 3
  123. 3

Monday, January 18, 2010

Introducing Streams

Streams are a special type of Iterable/Traversable whose elements are not evaluated until they are requested. Streams are normally constructed as functions.

A Scala List basically consists of the head element and the rest of the list. A Scala Stream is the head of the stream and a function that can construct the rest of the Stream. It is a bit more than this because each element is evaluated only once and stored in memory for future evaluations. That should be more clear after some examples.

As usual I created these examples with the Scala 2.8 REPL but I think most if not all should work in 2.7.

  1. scala> import Stream.cons          
  2. import Stream.cons
  3. /*
  4. Because streams are very functional in nature it is recommended that methods from the Stream object are used for creation
  5. This is a real boring example of creating a Stream.  Anything this simple should be a list.
  6. The important part is that cons take the value at the point and a function to return the rest of the
  7. stream NOT another stream.  
  8. */
  9. scala> val stream1 = cons(0,cons(1,Stream.empty))
  10. stream1: Stream.Cons[Int] = Stream(0, ?)
  11. scala> stream1 foreach {print _}                 
  12. 01
  13. /*
  14. This illustrates the similarity in design between Stream and list, again the difference is the entire list is created in a stream the second argument of cons is not evaluated until it is requested
  15. */
  16. scala> new ::(0, new ::(1,List.empty))
  17. res35: scala.collection.immutable.::[Int] = List(0, 1)
  18. /*
  19. To drive home the point of the similarities.  Here is an alternative declaration of a
  20. stream most similar to declaring a list
  21. */
  22. scala> val stream2 = 0 #:: 1 #:: Stream.empty    
  23. stream2: scala.collection.immutable.Stream[Int] = Stream(0, ?)
  24. scala> stream2 foreach {print _}
  25. 01
  26. scala> 0 :: 1 :: Nil
  27. res36: List[Int] = List(0, 1)
  28. /*
  29. A little more interesting now.  The accessing the second element will run the function.  Notice it is not evaluated until request
  30. */
  31. scala> val stream3 = cons (0, {    
  32.      | println("getting second element")
  33.      | cons(1,Stream.empty)
  34.      | })
  35. stream3: Stream.Cons[Int] = Stream(0, ?)
  36. scala> stream3(0)
  37. res56: Int = 0
  38. // function is evaluated
  39. scala> stream3(1)
  40. getting second element
  41. res57: Int = 1
  42. /* 
  43. Function is only evaluated once.  
  44. Important! This means that all elements in a Stream are loaded into a memory so
  45. it can cause a OutOfMemoryError if the stream is large
  46. */
  47. scala> stream3(1)
  48. res58: Int = 1
  49. scala> stream3(1)
  50. res59: Int = 1
  51. /*
  52. This creates an infinate stream then forces resolution of all elements
  53. */
  54. scala> Stream.from(100).force            
  55. java.lang.OutOfMemoryError: Java heap space
  56. // Alternative demonstration of laziness
  57. scala> val stream4 = 0 #:: {println("hi"); 1} #:: Stream.empty
  58. stream4: scala.collection.immutable.Stream[Int] = Stream(0, ?)
  59. scala> stream4(1)
  60. hi
  61. res2: Int = 1

A very common way to construct a Stream is to define a recursive method. Each recursive call constructs a new element in the stream. The method may or may not have a guard condition that terminates the stream.
  1. // construct a stream of random elements
  2. scala> def make : Stream[Int] = Stream.cons(util.Random.nextInt(10), make)
  3. make: Stream[Int]
  4. scala> val infinate = make                                                
  5. infinate: Stream[Int] = Stream(3, ?)
  6. scala> infinate(5)                                  
  7. res10: Int = 6
  8. scala> infinate(0)
  9. res11: Int = 3
  10. // Once evaluated each element does not change
  11. scala> infinate(5)
  12. res13: Int = 6
  13. // this function makes a stream that does terminate
  14. scala> def make(i:Int) : Stream[String] = {                  
  15.      | if(i==0) Stream.empty                                 
  16.      | else Stream.cons(i + 5 toString, make(i-1))           
  17.      | }
  18. make: (i: Int)Stream[String]
  19. scala> val finite = make(5)                       
  20. finite: Stream[String] = Stream(10, ?)
  21. scala> finite foreach print _                     
  22. 109876
  23. // One last demonstration of making a stream object
  24. scala> Stream.cons("10", make(2))
  25. res18: Stream.Cons[String] = Stream(10, ?)
  26. /*
  27. This method is dangerous as it forces the entire stream to be evaluated
  28. */
  29. scala> res18.size
  30. res19: Int = 3


This is only an introduction. I hope to add a few more topics that focus on Streams because they can be very powerful but are also more challenging to recognize where they should be used instead of a standard collection.