项目作者: erikerlandson

项目描述 :
A lightweight library for 'break' and 'continue' in Scala for-comprehensions
高级语言: Scala
项目地址: git://github.com/erikerlandson/breakable.git
创建时间: 2017-03-05T15:30:09Z
项目社区:https://github.com/erikerlandson/breakable

开源协议:Apache License 2.0

下载


breakable

A lightweight library for ‘break’ and ‘continue’ in Scala for-comprehensions

Features

  1. Functional programming using break and continue
  2. Fully compatible with Scala’s for-comprehensions, by virtue of its monadic design
  3. Results are represented as lazy computations, supporting logically infinite sequences
  4. break and continue operations take labels, allowing for easy control across multiple layers of nested looping
  5. Usable from inside for-comprehension loop bodies or with if clauses

Use breakable in your project

Download

SBT
  1. resolvers += "manyangled" at "https://dl.bintray.com/manyangled/maven/"
  2. libraryDependencies += "com.manyangled" %% "breakable" % "0.1.1"
API Doc

https://erikerlandson.github.io/breakable/latest/api/#package

Examples

The breakable library implements the break and continue operators on Scala sequences in for comprehensions. The result of a for comprehension over “breakable sequences” can be returned as a variety of standard Scala sequences:

  1. scala> import com.manyangled.breakable._
  2. import com.manyangled.breakable._
  3. scala> val bkb1 = for {
  4. | (x, xLab) <- (0 to 1000000).breakable // create a "breakable sequence"
  5. | } yield {
  6. | if (x % 2 == 1) continue(xLab) // continue to next
  7. | if (x > 10) break(xLab) // break out of the loop
  8. | x
  9. | }
  10. bkb1: com.manyangled.breakable.Breakable[Int] = com.manyangled.breakable.Breakable@7e02ffa5
  11. scala> bkb1.toList
  12. res0: List[Int] = List(0, 2, 4, 6, 8, 10)
  13. scala> bkb1.toVector
  14. res1: Vector[Int] = Vector(0, 2, 4, 6, 8, 10)
  15. scala> bkb1.toArray
  16. res2: Array[Int] = Array(0, 2, 4, 6, 8, 10)
  17. scala> bkb1.toIterator
  18. res3: Iterator[Int] = non-empty iterator
  19. scala> bkb1.toStream
  20. res4: Stream[Int] = Stream(0, ?)

Breakable sequences can be created with a method or function. Each breakable sequence exposes its own label (for example xLab and yLab, below). The break and continue operators take a label, and send the looping “control” to the corresponding sequence in the for comprehension. The break and continue operations may be used inside the yield, as in the previous example, or in if filters of a for comprehension, as in this example:

  1. scala> import com.manyangled.breakable._
  2. import com.manyangled.breakable._
  3. scala> val bkb2 = for {
  4. | (x, xLab) <- Stream.from(0).breakable // create breakable sequence with a method
  5. | (y, yLab) <- breakable(Stream.from(0)) // create with a function
  6. | if (x % 2 == 1) continue(xLab) // continue to next in outer "x" loop
  7. | if (y % 2 == 0) continue(yLab) // continue to next in inner "y" loop
  8. | if (x > 10) break(xLab) // break the outer "x" loop
  9. | if (y > x) break(yLab) // break the inner "y" loop
  10. | } yield (x, y)
  11. bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2
  12. scala> bkb2.toVector
  13. res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))

The result of any for comprehension over breakable sequences is represented as a lazy computation, as shown by this example having logically infinite output. This lazy output is stack-safe to evaluate, and is also memory-safe when traversed as an iterator:

  1. scala> val bkb3 = for {
  2. | (x, xLab) <- Stream.from(0).breakable
  3. | } yield {
  4. | if (x % 2 == 1) continue (xLab)
  5. | x
  6. | }
  7. bkb3: com.manyangled.breakable.Breakable[Int] = com.manyangled.breakable.Breakable@65aad230
  8. scala> bkb3.toStream.take(10).toVector
  9. res0: Vector[Int] = Vector(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
  10. scala> bkb3.toIterator.take(100000000).length
  11. res1: Int = 100000000

An example of ‘foreach’ mode (without yield). Computations using this mode are not lazy,
since the semantics are to execute the loop body.

  1. scala> import com.manyangled.breakable._
  2. import com.manyangled.breakable._
  3. scala> for {
  4. | (x, xLab) <- Stream.from(0).breakable
  5. | } {
  6. | if (x % 2 == 1) continue(xLab)
  7. | if (x > 10) break(xLab)
  8. | println(s"x= $x")
  9. | }
  10. x= 0
  11. x= 2
  12. x= 4
  13. x= 6
  14. x= 8
  15. x= 10