2014 JavaOne University: Functional Programming in Scala

written in

This blog post correponds to my 2014 JavaOne University course.

The content of this blog post (deliberately) does not go into all details.

Course content

This course is about functional programming patterns in general, and functional programming patterns related to datasources in particular.

Course approach

The course describes a Scala library that formalizes functional datasource patterns.

Back to school

One of the main goals of this course is to illustrate that datasources are closely related to concepts you learned in school.

Multiplication

Most probably, you remember the multiplication operator

  • * for integers
  • and for booleans

Most probably, you also remember that the multiplication operators above have a neutral element

  • 1 for integers
  • true for booleans

Multiplicative data

At this moment we do a big (not to say gigantic) step forwards by, somehow, adding data to the multiplication operator above. An important question to answer is: what should be the data semantics associated with multiplication?

Multiplicative data are formalized by the trait’s below

HasOne (HasOne.scala) download
1
2
3
4
5
6
7
8
  trait HasOneModule
    extends RunnableModule {
    type D[Z] <: HasOne[Z]
    def one[Z]: Z => D[Z]
    trait HasOne[A]
      extends Runnable[A] { da: D[A] =>
    }
  }
Multiplicative (Multiplicative.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  trait MultiplicativeModule
    extends HasOneModule {
    type D[Z] <: Multiplicative[Z]
    trait Multiplicative[A]
      extends HasOne[A] { da: D[A] =>
      def and[B](d_a2b: => D[A => B]): D[B]
      def end[B](a2b: A => B): D[B] =
        da and one(a2b)
      def **[B](db: => D[B]): D[A ** B] =
        da and (
          db end {
            b =>
              a =>
                (a, b)
          })
    }
  }

where Runnable is formalized by the trait below

Runnable (Runnable.scala) download
1
2
3
4
5
6
7
8
  trait RunnableModule {
    type D[Z] <: Runnable[Z]
    type In
    type Out[Z]
    trait Runnable[A] { da: D[A] =>
      def run(in: In): Out[A]
    }
  }

and the Product Type Z ** Y is defined as

Product (Product.scala) download
1
  type **[Z, Y] = (Z, Y)

trait HasOneModule

  • declares the type D[Z] as a subtype of Multiplicative[Z]
  • declares the function one
    • given a value z of type Z, one(z) should produce z

trait Multiplicative[A]

  • declares the method and
    • given da, somehow producing values of type A, and d_a2b, somehow producing values of type A => B, da and d_a2b should, somehow, using the values produced by da and d_a2b, produce values of type B
  • defines the method end in terms of and and one
  • defines the method ** in terms of and and end

Note: This “declares the type D[Z] as a subtype of Something[Z]” is such a common theme that we are not going to repeat it over and over again.

Domain Specific Language

The functions and methods of MultiplicativeModule constitute a DSL.

Note: This “the functions and methods of SomethingModule constitute a DSL” is such a common theme that we are not going to repeat it over and over again.

Multiplicative data usage

The code below defines some examples that make use of the multiplicative data DSL

MultiplicativeUsage (MultiplicativeUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  trait MultiplicativeUsage {
    import Lib.MultiplicativeModule

    val mm: MultiplicativeModule
    import mm._

    val multiplicative01: Int => D[Int] => D[Int ** Int] = {
      case i =>
        di =>
          one(i) ** di
    }

    val multiplicative02: Int ** Int => D[Int] => D[Int ** Int ** Int] = {
      case (i1, i2) =>
        di =>
          one(i1) ** one(i2) ** di
    }

    val multiplicative03: Int ** Int ** Int => D[Int] => D[Int ** Int ** Int ** Int] = {
      case ((i1, i2), i3) =>
        di =>
          one(i1) ** one(i2) ** one(i3) ** di
    }

    val multiplicative04: Int ** Int => D[Int] => D[Int ** (Int ** Int)] = {
      case (i1, i2) =>
        di =>
          one(i1) ** (one(i2) ** di)
    }

    val multiplicative05: Int ** Int => D[Int] = {
      case (i1, i2) =>
        one(i1) and {
          one(i2) end {
            i2 =>
              i1 =>
                i1 + i2
          }
        }
    }

    val multiplicative06: Int ** Int ** Int => D[Int] = {
      case ((i1, i2), i3) =>
        one(i1) and {
          one(i2) and {
            one(i3) end {
              i3 =>
                i2 =>
                  i1 =>
                    i1 + i2 + i3
            }
          }
        }
    }

    val multiplicative07: Int ** Int ** Int ** Int => D[Int] = {
      case (((i1, i2), i3), i4) =>
        one(i1) and {
          one(i2) and {
            one(i3) and {
              one(i4) end {
                i4 =>
                  i3 =>
                    i2 =>
                      i1 =>
                        i1 + i2 + i3 + i4
              }
            }
          }
        }
    }

    lazy val example01 = multiplicative01(1)(one(2))
    lazy val example02 = multiplicative02((1, 2))(one(3))
    lazy val example03 = multiplicative03(((1, 2), 3))(one(4))
    lazy val example04 = multiplicative04((1, 2))(one(3))
    lazy val example05 = multiplicative05((1, 2))
    lazy val example06 = multiplicative06(((1, 2), 3))
    lazy val example07 = multiplicative07((((1, 2), 3), 4))

    val in: In

    def multiplicative_usage() {
      println(example01.run(in))
      println(example02.run(in))
      println(example03.run(in))
      println(example04.run(in))
      println(example05.run(in))
      println(example06.run(in))
      println(example07.run(in))
    }
  }

Think about expressions like one(i1) ** one(i2) ** di as generalizations of expressions like a * b * x that also produce accumulated data.

Above we defined abstract examples that make use of the multiplicative data DSL before defining any concrete multiplicative data instance. Think of it as programming to an interface.

Below is a trivial Runnable implementation

TrivialRunnableModule (TrivialRunnableModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
  trait TrivialRunnableModule
    extends RunnableModule {
    type D[Z] <: TrivialRunnable[Z]
    type In = Unit
    type Out[Z] = D[Z]
    trait TrivialRunnable[A]
      extends Runnable[A] { da: D[A] =>
      override def run(in: In): Out[A] =
        da
    }
  }

The simplest MultiplicativeModule instance one can think of is one along the following lines

1
2
3
4
5
6
object OneModule {
  // ...
  case class One[A](a: A) {
  // ...
  }
}

Think of One[Z] as a data source that produces one value.

Given a One[Z] instance it is possible to define

OneMultiplicativeUsage (OneMultiplicativeUsage.scala) download
1
2
3
4
5
6
  object OneMultiplicativeUsage
    extends MultiplicativeUsage {
    import Instances.OneModule
    override val mm: OneModule.type = OneModule
    override val in = ()
  }

and use it as follows

OneMultiplicativeUsageInApp (OneMultiplicativeUsageInApp.scala) download
1
2
3
4
    {
      import Usage.OneMultiplicativeUsage._
      multiplicative_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
7
{ (1,2) }
{ ((1,2),3) }
{ (((1,2),3),4) }
{ (1,(2,3)) }
{ 3 }
{ 6 }
{ 10 }

Addition

Most probably, you remember the addition operator

  • + for integers
  • or for booleans

Most probably, you also remember that the addition operators above have a neutral element

  • 0 for integers
  • false for booleans

Additive data

Again, an important question to answer is: what should be the data semantics associated with addition be?

Additive data are formalized by the trait’s below

HasZero (HasZero.scala) download
1
2
3
4
5
6
7
8
  trait HasZeroModule
    extends RunnableModule {
    type D[Z] <: HasZero[Z]
    def zero[Z]: Unit => D[Z]
    trait HasZero[A]
      extends Runnable[A] { da: D[A] =>
    }
  }
Additive (Additive.scala) download
1
2
3
4
5
6
7
8
9
10
  trait AdditiveModule
    extends HasZeroModule {
    type D[Z] <: Additive[Z]
    trait Additive[A]
      extends HasZero[A] { da: D[A] =>
      def take(n: Int): D[A]
      def or(da1: => D[A]): D[A]
      def ++[B](db: => D[B]): D[A ++ B]
    }
  }

where the Sum Type Z ++ Y is defined as

Sum (Sum.scala) download
1
  type ++[Z, Y] = Either[Z, Y]

trait HasZeroModule

  • declares the function zero
    • zero(()) should produce no values

trait Additive[A]

  • declares the method or
    • given da, somehow producing values of type A, and da1, somehow producing values of type A, da or da1 should, somehow, produce the values produced by da or produce the values produced by da1
  • declares the method ++, defined later in terms of (among others) or

Note: Do not think of or as an exclusive one, think of or as an inclusive one.

Note: Additive[A] also has a method take

  • when making use of recursion, infinitely many values can be produced

Polynomial data

Polynomial data are formalized by the trait below as a combination of Multiplicative data and Additive data

Polynomial (Polynomial.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  trait PolynomialModule
    extends MultiplicativeModule
    with AdditiveModule {
    type D[Z] <: Polynomial[Z]
    trait Polynomial[A]
      extends Multiplicative[A]
      with Additive[A] { da: D[A] =>
      override def ++[B](db: => D[B]): D[A ++ B] = {
        val dl: D[A ++ B] =
          da end {
            a =>
              Left(a)
          }
        val dr: D[A ++ B] =
          db end {
            b =>
              Right(b)
          }
        dl or dr
      }
    }
  }

trait Polynomial[A]

  • defines the method ++ in terms of end and or

Polynomial data usage

The code below defines some examples that make use of the polynomial data DSL

PolynomialUsage (PolynomialUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  trait PolynomialUsage {
    import Lib.PolynomialModule

    val pm: PolynomialModule
    import pm._

    val polynomial01a: Int ** Int => D[Int] => D[Int ** Int] = {
      case (i1, i2) =>
        di =>
          one(i1) ** one(i2) or (one(i1) or one(i2)) ** di or di ** di
    }

    val polynomial01b: Int ** Int => D[Int] => D[Int ** Int] = {
      case (i1, i2) =>
        di =>
          di ** di or di ** (one(i1) or one(i2)) or one(i1) ** one(i2)
    }

    val polynomial03a: Int ** Int => D[Int] => D[Int ** Int] = {
      case (i1, i2) =>
        di =>
          (one(i1) or di) ** (one(i2) or di)
    }

    val polynomial03b: Int ** Int => D[Int] => D[Int ** Int] = {
      case (i1, i2) =>
        di =>
          (di or one(i1)) ** (di or one(i2))
    }

    val polynomial02a: Int ** Int => D[Int] => D[Int ** Int ++ ((Int ++ Int) ** Int) ++ (Int ** Int)] = {
      case (i1, i2) =>
        di =>
          (one(i1) ** one(i2)) ++ (one(i1) ++ one(i2)) ** di ++ di ** di
    }

    val polynomial02b: Int ** Int => D[Int] => D[Int ** Int ++ (Int ** (Int ++ Int)) ++ (Int ** Int)] = {
      case (i1, i2) =>
        di =>
          di ** di ++ di ** (one(i1) ++ one(i2)) ++ (one(i1) ** one(i2))
    }

    val polynomial04a: Int ** Int => D[Int] => D[(Int ++ Int) ** (Int ++ Int)] = {
      case (i1, i2) =>
        di =>
          (one(i1) ++ di) ** (one(i2) ++ di)
    }

    val polynomial04b: Int ** Int => D[Int] => D[(Int ++ Int) ** (Int ++ Int)] = {
      case (i1, i2) =>
        di =>
          (di ++ one(i1)) ** (di ++ one(i2))
    }

    lazy val example01 = polynomial01a((1, 2))(zero(()))
    lazy val example02 = polynomial01a((1, 2))(one(3))
    lazy val example03 = polynomial01b((1, 2))(zero(()))
    lazy val example04 = polynomial01b((1, 2))(one(3))
    lazy val example05 = polynomial03a((1, 2))(zero(()))
    lazy val example06 = polynomial03a((1, 2))(one(3))
    lazy val example07 = polynomial03b((1, 2))(zero(()))
    lazy val example08 = polynomial03b((1, 2))(one(3))
    lazy val example09 = polynomial02a((1, 2))(zero(()))
    lazy val example10 = polynomial02a((1, 2))(one(3))
    lazy val example11 = polynomial02b((1, 2))(zero(()))
    lazy val example12 = polynomial02b((1, 2))(one(3))
    lazy val example13 = polynomial04a((1, 2))(zero(()))
    lazy val example14 = polynomial04a((1, 2))(one(3))
    lazy val example15 = polynomial04b((1, 2))(zero(()))
    lazy val example16 = polynomial04b((1, 2))(one(3))

    val in: In

    def polynomial_usage() {
      println(example01.run(in))
      println(example02.run(in))
      println(example03.run(in))
      println(example04.run(in))
      println(example05.run(in))
      println(example06.run(in))
      println(example07.run(in))
      println(example08.run(in))

      println(example09.run(in))
      println(example10.run(in))
      println(example11.run(in))
      println(example12.run(in))
      println(example13.run(in))
      println(example14.run(in))
      println(example15.run(in))
      println(example16.run(in))
    }

    val nats: Int => D[Int] = {
      case i =>
        one(i) or nats(i + 1)
    }

    val fibs: Int ** Int => D[Int] = {
      case (i1, i2) =>
        one(i1) or fibs((i2, (i1 + i2)))
    }

    def recursion_and_take_usage() {
      lazy val firstTenNats: D[Int] = nats(0).take(10)
      lazy val firstNineFibs: D[Int] = fibs((0, 1)).take(9)

      println(firstTenNats.run(in))
      println(firstNineFibs.run(in))
    }

  }

Again, think about expressions like one(i1) ** one(i2) ++ (one(i1) ++ one(i2)) ** di ++ di ** di, resp. (one(i1) ++ di) ** (one(i2) ++ di) as generalizations of expressions like a * b + (a + b) * x + x * x resp. (a + x) * (b + x) that also produce accumulated data.

The simplest PolynomialModule instance one can think of is one along the following lines

1
2
3
4
5
6
7
8
object ZeroOrOneModule {
  // ...
  sealed trait ZeroOrOne[A] {
  // ...
  }
  private case class Zero[A]() extends ZeroOrOne[A]()
  private case class One[A](a: A) extends ZeroOrOne[A]
}

Think of ZeroOrOne[Z] as a data source that produces zero or one values.

Given a ZeroOrOne[Z] instance it is possible to define

ZeroOrOnePolynomialUsage (ZeroOrOnePolynomialUsage.scala) download
1
2
3
4
5
6
  object ZeroOrOnePolynomialUsage
    extends PolynomialUsage {
    import Instances.ZeroOrOneModule
    override val pm: ZeroOrOneModule.type = ZeroOrOneModule
    override val in = ()
  }

and use it as follows

ZeroOrOnePolynomialUsageInApp (ZeroOrOnePolynomialUsageInApp.scala) download
1
2
3
4
5
    {
      import Usage.ZeroOrOnePolynomialUsage._
      polynomial_usage()
      recursion_and_take_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{ (1,2) }
{ (1,2) }
{ (1,2) }
{ (3,3) }
{ (1,2) }
{ (1,2) }
{ (1,2) }
{ (3,3) }
{ Left(Left((1,2))) }
{ Left(Left((1,2))) }
{ Right((1,2)) }
{ Left(Left((3,3))) }
{ (Left(1),Left(2)) }
{ (Left(1),Left(2)) }
{ (Right(1),Right(2)) }
{ (Left(3),Left(3)) }
{ 0 }
{ 0 }

A more complex PolynomialModule instance is one along the following lines

1
2
3
4
5
6
7
8
object ZeroOrMoreModule {
  // ...
  sealed trait ZeroOrMore[A] {
  // ...
  }
  private case class Zero[A]() extends ZeroOrMore[A]
  private case class More[A](a_n_u2da: A ** (Unit => ZeroOrMore[A])) extends ZeroOrMore[A]
}

Think of ZeroOrMore[Z] as a data source that produces zero or more values.

Given a ZeroOrMore[Z] instance it is possible to define

ZeroOrMorePolynomialUsage (ZeroOrMorePolynomialUsage.scala) download
1
2
3
4
5
6
  object ZeroOrMorePolynomialUsage
    extends PolynomialUsage {
    import Instances.ZeroOrMoreModule
    override val pm: ZeroOrMoreModule.type = ZeroOrMoreModule
    override val in = ()
  }

and use it as follows

ZeroOrMorePolynomialUsageInApp (ZeroOrMorePolynomialUsageInApp.scala) download
1
2
3
4
5
    {
      import Usage.ZeroOrMorePolynomialUsage._
      polynomial_usage()
      recursion_and_take_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[ (1,2) ]
[ (1,2) (1,3) (2,3) (3,3) ]
[ (1,2) ]
[ (3,3) (3,1) (3,2) (1,2) ]
[ (1,2) ]
[ (1,2) (1,3) (3,2) (3,3) ]
[ (1,2) ]
[ (3,3) (3,2) (1,3) (1,2) ]
[ Left(Left((1,2))) ]
[ Left(Left((1,2))) Left(Right((Left(1),3))) Left(Right((Right(2),3))) Right((3,3)) ]
[ Right((1,2)) ]
[ Left(Left((3,3))) Left(Right((3,Left(1)))) Left(Right((3,Right(2)))) Right((1,2)) ]
[ (Left(1),Left(2)) ]
[ (Left(1),Left(2)) (Left(1),Right(3)) (Right(3),Left(2)) (Right(3),Right(3)) ]
[ (Right(1),Right(2)) ]
[ (Left(3),Left(3)) (Left(3),Right(2)) (Right(1),Left(3)) (Right(1),Right(2)) ]
[ 0 1 2 3 4 5 6 7 8 9 ]
[ 0 1 1 2 3 5 8 13 21 ]

Datasource

You are, most probably, used to think of

  • functions in terms of applying them to values as in a2b(a) or, equivalently, a2b apply a

You can also think of

  • values in terms of binding them to functions as in a bind a2b

The method bind below, defined in terms of apply, formalizes binding

Bind (Bind.scala) download
1
2
3
4
  implicit class Bind[Z](z: Z) {
    def bind[Y](z2y: Z => Y): Y =
      z2y apply z
  }

Data sources, formalized by the trait below, generalize binding

Source (Source.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  trait SourceModule
    extends MultiplicativeModule {
    type D[Z] <: Source[Z]
    def join[Z]: D[D[Z]] => D[Z] =
      d_dz =>
        d_dz bnd identity
    trait Source[A]
      extends Multiplicative[A] { da: D[A] =>
      def bnd[B](a2db: A => D[B]): D[B]
      override def and[B](d_a2b: => D[A => B]): D[B] =
        da bnd {
          a =>
            d_a2b bnd {
              a2b =>
                a bind a2b bind one
            }
        }
      def switch[B](p_a: Predicate[A])(t_a2db: A => D[B])(f_a2db: A => D[B]): D[B] =
        da bnd {
          a =>
            (a bind p_a) match {
              case true =>
                a bind t_a2db
              case false =>
                a bind f_a2db
            }
        }
    }
  }

where the Predicate Type Predicate[Z] is defined as

Predicate (Predicate.scala) download
1
  type Predicate[A] = A => Boolean

Note: We made use of bind just to show that it is as simple to use as apply.

trait SourceModule

  • defines the function join in terms of bnd

trait Source[A]

  • declares the method bnd
    • given da, somehow producing values of type A, and a2db of type A => D[B], da bnd a2db should, somehow, using a2b and the values produced by da, produce values of type B
  • defines the method and in terms of bnd and one
  • defines the method switch in terms of bnd

The definitions of join and and are the most natural ones you can possibly come up with to get the types right.

About abstraction, power of expression and implementation flexibility

abstraction

and is more abstract than bnd

  • and is defined interms of bnd

power of expression

bnd, being less abstract, has more power of expression than and

  • When making use of bnd, values are immediately in scope from the outermost scope all the way down to the innermost scope.
  • When making use of and, values are only in scope at the innermost scope.

The method switch illustrates this power of expression: a can be used to decide how to proceed.

implementation flexibility

and, being more abstract, has more implementation flexibility than bnd

  • The definition of and is a default definition that can be overridden for specific implementations.

Datasource usage

The code below defines some examples that make use of the datasource DSL

SourceUsage (SourceUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  trait SourceUsage {
    import Lib.SourceModule

    val sm: SourceModule
    import sm._

    val source01: Int ** Int => D[Int ** Int] = {
      case (i1, i2) =>
        one(i1) bnd {
          z =>
            one(i2) end {
              y =>
                (z, y)
            }
        }
    }

    val source02: Int ** Int ** Int => D[Int ** Int ** Int] = {
      case ((i1, i2), i3) =>
        one(i1) bnd {
          z =>
            one(i2) bnd {
              y =>
                one(i3) end {
                  x =>
                    ((z, y), x)
                }
            }
        }
    }

    val source03: Int ** Int ** Int ** Int => D[Int ** Int ** Int ** Int] = {
      case (((i1, i2), i3), i4) =>
        one(i1) bnd {
          z =>
            one(i2) bnd {
              y =>
                one(i3) bnd {
                  x =>
                    one(i4) end {
                      w =>
                        (((z, y), x), w)
                    }
                }
            }
        }
    }

    val source04: Int => D[Int] = {
      case i =>
        one(i).switch(_ < 10) {
          _ =>
            one(i)
        } {
          _ =>
            one(i * i)
        }
    }

    lazy val example01 = source01((1, 2))
    lazy val example02 = source02(((1, 2), 3))
    lazy val example03 = source03((((1, 2), 3), 4))
    lazy val example04 = source04(5)
    lazy val example05 = source04(11)

    val in: In

    def source_usage() {
      println(example01.run(in))
      println(example02.run(in))
      println(example03.run(in))
      println(example04.run(in))
      println(example05.run(in))
    }

  }

Given a One instance it is possible to define

OneSourceUsage (OneSourceUsage.scala) download
1
2
3
4
5
6
  object OneSourceUsage
    extends SourceUsage {
    import Instances.OneModule
    override val sm: OneModule.type = OneModule
    override val in = ()
  }

and use it as follows

OneSourceUsageInApp (OneSourceUsageInApp.scala) download
1
2
3
4
    {
      import Usage.OneSourceUsage._
      source_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
{ (1,2) }
{ ((1,2),3) }
{ (((1,2),3),4) }
{ 5 }
{ 121 }

Polynomial datasource

Polynomial datasources are formalized by the trait below as a combination of Datasources and Polynomial data

PolynomialSource (PolynomialSource.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  trait PolynomialSourceModule
    extends SourceModule
    with PolynomialModule {
    type D[Z] <: PolynomialSource[Z]
    trait PolynomialSource[A]
      extends Source[A]
      with Polynomial[A] { da: D[A] =>
      def filter(pa: Predicate[A]): D[A] =
        da.switch(pa) {
          a =>
            a bind one
        } {
          a =>
            () bind zero
        }
    }
  }

trait PolynomialSource[A]

  • defines the method filter in terms of switch, one and zero

Again, the definition of filter is the most natural one you can possibly come up with to get the type right.

Polynomial datasource usage

The code below defines some examples that make use of the polynomial datasource DSL

PolynomialSourceUsage (PolynomialSourceUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  trait PolynomialSourceUsage {
    import Lib.PolynomialSourceModule

    val psm: PolynomialSourceModule
    import psm._

    val ps01: Int ** Int => D[Int] => D[Int ** Int] = {
      case (i1, i2) =>
        di =>
          (di bnd {
            i =>
              di end {
                j =>
                  (i, j)
              }
          }) or
            (di bnd {
              i =>
                (one(i1) or one(i2)) end {
                  j =>
                    (i, j)
                }
            }) or
            (one(i1) bnd {
              i =>
                one(i2) end {
                  j =>
                    (i, j)
                }
            })
    }

    val ps02: Int ** Int => D[Int] => D[Int ** Int ++ (Int ** (Int ++ Int)) ++ (Int ** Int)] = {
      case (i1, i2) =>
        di =>
          (di bnd {
            i =>
              di end {
                j =>
                  (i, j)
              }
          }) ++
            (di bnd {
              i =>
                (one(i1) ++ one(i2)) end {
                  j =>
                    (i, j)
                }
            }) ++
            (one(i1) bnd {
              i =>
                one(i2) end {
                  j =>
                    (i, j)
                }
            })
    }

    val fps01: Int ** Int => D[Int] => D[Int ** Int] = {
      case (i1, i2) =>
        di =>
          ps01((i1, i2))(di).filter {
            case (i1, i2) =>
              i1 == i2
          }
    }

    val fps02: Int ** Int => D[Int] => D[Int ** Int ++ (Int ** (Int ++ Int)) ++ (Int ** Int)] = {
      case (i1, i2) =>
        di =>
          ps02((i1, i2))(di).filter {
            case Right(_) =>
              true
            case _ =>
              false
          }
    }

    lazy val example01 = ps01((1, 2))(zero(()))
    lazy val example02 = ps01((1, 2))(one(3))
    lazy val example03 = ps02((1, 2))(zero(()))
    lazy val example04 = ps02((1, 2))(one(3))
    lazy val example05 = fps01((1, 2))(zero(()))
    lazy val example06 = fps01((1, 2))(one(3))
    lazy val example07 = fps02((1, 2))(zero(()))
    lazy val example08 = fps02((1, 2))(one(3))

    val in: In

    def polynomial_source_usage() {
      println(example01.run(in))
      println(example02.run(in))
      println(example03.run(in))
      println(example04.run(in))
      println(example05.run(in))
      println(example06.run(in))
      println(example07.run(in))
      println(example08.run(in))
    }

  }

Given a ZeroOrOne instance it is possible to define

ZeroOrOnePolynomialSourceUsage (ZeroOrOnePolynomialSourceUsage.scala) download
1
2
3
4
5
6
  object ZeroOrOnePolynomialSourceUsage
    extends PolynomialSourceUsage {
    import Instances.ZeroOrOneModule
    override val psm: ZeroOrOneModule.type = ZeroOrOneModule
    override val in = ()
  }

and use it as follows

ZeroOrOnePolynomialSourceUsageInApp (ZeroOrOnePolynomialSourceUsageInApp.scala) download
1
2
3
4
    {
      import Usage.ZeroOrOnePolynomialSourceUsage._
      polynomial_source_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
7
8
{ (1,2) }
{ (3,3) }
{ Right((1,2)) }
{ Left(Left((3,3))) }
{ }
{ (3,3) }
{ Right((1,2)) }
{ }

Given a ZeroOrMore instance it is possible to define

ZeroOrMorePolynomialSourceUsage (ZeroOrMorePolynomialSourceUsage.scala) download
1
2
3
4
5
6
  object ZeroOrMorePolynomialSourceUsage
    extends PolynomialSourceUsage {
    import Instances.ZeroOrMoreModule
    override val psm: ZeroOrMoreModule.type = ZeroOrMoreModule
    override val in = ()
  }

and use it as follows

ZeroOrMorePolynomialSourceUsageInApp (ZeroOrMorePolynomialSourceUsageInApp.scala) download
1
2
3
4
    {
      import Usage.ZeroOrMorePolynomialSourceUsage._
      polynomial_source_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
7
8
[ (1,2) ]
[ (3,3) (3,1) (3,2) (1,2) ]
[ Right((1,2)) ]
[ Left(Left((3,3))) Left(Right((3,Left(1)))) Left(Right((3,Right(2)))) Right((1,2)) ]
[ ]
[ (3,3) ]
[ Right((1,2)) ]
[ Right((1,2)) ]

Reducible data

Reducible data are formalized by the trait below

Reducible (Reducible.scala) download
1
2
3
4
5
6
7
8
  trait ReducibleModule {
    type D[Z] <: Reducible[Z]
    type Reducer[Z, R]
    def identityReducer[Z]: Reducer[Z, D[Z]]
    trait Reducible[A] { da: D[A] =>
      def reducedBy[R](a_r2_r: Reducer[A, R]): R
    }
  }

trait ReducibleModule

  • declares the type Reducer[Z, R]
  • declares the reducer identityReducer
    • given dz, dz reducedBy identityReducer should reduce to dz

trait Reducible[A]

  • declares the method reducedBy
    • given da, somehow producing values of type A, and a_r2_r, somehow reducing those values to a result of type R, da reducedBy a_r2_r should reduce those values to that result

Traversable data

Traversable data are formalized by the trait below

Traversable (Traversable.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
  trait TraversableModule
    extends ReducibleModule {
    type D[Z] <: Traversable[Z]
    type MM = MultiplicativeModule
    def lift[Z, Y, R](mm: MM)(z2mmy: Z => mm.D[Y]): Reducer[Y, R] => Reducer[Z, mm.D[R]]
    def swap[Z](mm: MM): D[mm.D[Z]] => mm.D[D[Z]] =
      _.foreach(mm)(identity)(identityReducer)
    trait Traversable[A]
      extends Reducible[A] { da: D[A] =>
      def foreach[B, R](mm: MM)(a2mmdb: A => mm.D[B]): Reducer[B, R] => mm.D[R] =
        lift(mm)(a2mmdb) andThen da.reducedBy
    }
  }

trait TraversableModule

  • defines the type MM as an alias of the type MultiplicativeModule
  • declares the function lift
    • given an mm of type MM and a function z2mmy of type Z => mm.D[Y], lift should lift a reducer of type Reducer[Y, R] to a reducer of type Reducer[Z, mm.D[R]]
  • defines the function swap, in terms of foreach, identity and identityReducer

trait Traversable[A]

  • defines the method foreach in terms of lift and reducedBy

Again, the definitions of swap and foreach are the most natural ones you can possibly come up with to get the type right.

Traversable polynomial data are formalized by the trait below

TraversablePolynomial (TraversablePolynomial.scala) download
1
2
3
4
5
6
7
8
9
  trait TraversablePolynomialModule
    extends PolynomialModule
    with TraversableModule {
    type D[Z] <: TraversablePolynomial[Z]
    trait TraversablePolynomial[A]
      extends Polynomial[A]
      with Traversable[A] { da: D[A] =>
    }
  }

Traversable datasources are formalized by the trait below

TraversableSource (TraversableSource.scala) download
1
2
3
4
5
6
7
8
9
  trait TraversableSourceModule
    extends SourceModule
    with TraversableModule {
    type D[Z] <: TraversableSource[Z]
    trait TraversableSource[A]
      extends Source[A]
      with Traversable[A] { da: D[A] =>
    }
  }

Traversable polynomial datasources are formalized by the trait below

TraversablePolynomialSource (TraversablePolynomialSource.scala) download
1
2
3
4
5
6
7
8
9
  trait TraversablePolynomialSourceModule
    extends TraversablePolynomialModule
    with PolynomialSourceModule {
    type D[Z] <: TraversablePolynomialSource[Z]
    trait TraversablePolynomialSource[A]
      extends TraversablePolynomial[A]
      with PolynomialSource[A] { da: D[A] =>
    }
  }

Traversable polynomial data (and polynomial data) usage

The code below defines some examples that make use of the traversable polynomial data (and polynomial data) DSL

TraversablePolynomialAndPolynomialUsage (TraversablePolynomialAndPolynomialUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  trait TraversablePolynomialAndPolynomialUsage {
    import Lib.TraversablePolynomialModule
    import Lib.PolynomialModule

    val tpm: TraversablePolynomialModule
    val pm: PolynomialModule

    val tp_p: pm.D[Int] ** pm.D[Int] ** pm.D[Int] => tpm.D[pm.D[Int]] = {
      case ((pmd01, pmd02), pmd03) =>
        tpm.one(pmd01) or tpm.one(pmd02) or tpm.one(pmd03)
    }

    lazy val p_tp: pm.D[Int] ** pm.D[Int] ** pm.D[Int] => pm.D[tpm.D[Int]] =
      tp_p andThen tpm.swap(pm)

    lazy val example01: pm.D[Int] ** pm.D[Int] ** pm.D[Int] =
      ((pm.one(1), pm.one(2)), pm.one(3))
    lazy val example02: pm.D[Int] ** pm.D[Int] ** pm.D[Int] =
      ((pm.zero(()), pm.one(2)), pm.one(3))
    lazy val example03: pm.D[Int] ** pm.D[Int] ** pm.D[Int] =
      ((pm.one(1), pm.zero(())), pm.zero(()))

    val tpm_in: tpm.In
    val pm_in: pm.In

    def traversablePolynomial_and_polynomial_usage() {
      println(tp_p(example01).run(tpm_in))
      println(p_tp(example01).run(pm_in))
      println(tp_p(example02).run(tpm_in))
      println(p_tp(example02).run(pm_in))
      println(tp_p(example03).run(tpm_in))
      println(p_tp(example03).run(pm_in))
    }
  }

Given ZeroOrMore and ZeroOrOne instances it is possible to define

ZeroOrMoreAndZeroOrOneUsage (ZeroOrMoreAndZeroOrOneUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
  object ZeroOrMoreAndZeroOrOneUsage
    extends TraversablePolynomialAndPolynomialUsage {
    import Instances.ZeroOrMoreModule
    import Instances.ZeroOrOneModule

    override val tpm: ZeroOrMoreModule.type = ZeroOrMoreModule
    override val pm: ZeroOrOneModule.type = ZeroOrOneModule

    override val tpm_in = ()
    override val pm_in = ()
  }

and use it as follows

ZeroOrMoreAndZeroOrOneUsageInApp (ZeroOrMoreAndZeroOrOneUsageInApp.scala) download
1
2
3
4
    {
      import Usage.ZeroOrMoreAndZeroOrOneUsage._
      traversablePolynomial_and_polynomial_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
[ { 1 } { 2 } { 3 } ]
{ [ 1 2 3 ] }
[ { } { 2 } { 3 } ]
{ }
[ { 1 } { } { } ]
{ }

Note We swapped to a non-zero result if and only if all values are non-zero.

as such

  • ZeroOrOne could be used as a success or failure mechanism

but

  • ZeroOrOne should be used for what it is meant for: zero or one values

Failure handling strategies

Below are two failure handling strategies

  • fail fast
  • fail slow and accumulate failure information

Monoids

Accumulation is modeled by the monoid concept.

Monoids are formalized by the trait below

Monoid (Monoid.scala) download
1
2
3
4
5
6
7
  trait MonoidModule {
    type M <: Monoid
    def neutral: M
    trait Monoid { m: M =>
      def operator(m1: M): M
    }
  }

trait MonoidModule

  • declares the type M as a subtype of Monoid
  • declares the neutral element of type M

trait Monoid

  • declares the method operator
    • given an element m of type M and an element m1 of type M, m operator m1 should be an element of type M

Strings as monoids are formalized by the instance below

StringMonoid (StringMonoid.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
  object StringMonoidModule
    extends MonoidModule {
    type M = StringMonoid
    override def neutral =
      StringMonoid("")
    case class StringMonoid(s: String)
      extends Monoid { m: M =>
      override def operator(m1: M) =
        StringMonoid(s"${m.s} ${m1.s}")
      override def toString =
        s
    }
  }

Failing data

Failing data are formalized by the trait below

Failing (Failing.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
  trait FailingModule
    extends HasZeroModule {
    val mm: MonoidModule
    import mm._
    type D[Z] <: Failing[Z]
    def fail[Z]: M => D[Z]
    override def zero[Z]: Unit => D[Z] =
      _ => fail(neutral)
    trait Failing[A]
      extends HasZero[A] { da: D[A] =>
    }
  }

trait FailingModule

  • declares a mm of type MonoidModule and does an appropriate import
  • declares the function fail
    • given an element m of type M, fail(m) should, somehow, not yield any values, but fail instead with failure information m
  • defines the function zero in terms of fail and neutral

Polynomial failing data are formalized by the trait below

PolynomialFailing (PolynomialFailing.scala) download
1
2
3
4
5
6
7
8
9
  trait PolynomialFailingModule
    extends PolynomialModule
    with FailingModule {
    type D[Z] <: PolynomialFailing[Z]
    trait PolynomialFailing[A]
      extends Polynomial[A]
      with Failing[A] { da: D[A] =>
    }
  }

The simplest PolynomialFailingModule instance one can think of is one along the following lines

1
2
3
4
5
6
7
8
trait SuccessOrFailureModule {
  // ...
  sealed trait SuccessOrFailure[A] {
  // ...
  }
  private case class Failure[A](m: M) extends SuccessOrFailure[A]
  private case class Success[A](a: A) extends SuccessOrFailure[A]
}

Think of SuccessOrFailure[Z] as a data source that produces one value or fails.

Note: SuccessOrFailureModule is a trait (mm still needs to be defined).

The simplest SuccessOrFailureModule instance one can think of is the following

StringSuccessOrFailureModule (StringSuccessOrFailureModule.scala) download
1
2
3
4
  object StringSuccessOrFailureModule
    extends SuccessOrFailureModule {
    val mm: StringMonoidModule.type = StringMonoidModule
  }

Traversable polynomial data (and polynomial failing data) usage

The code below defines some examples that make use of the traversable polynomial data (and polynomial failing data) DSL

TraversablePolynomialAndPolynomialFailingUsage (TraversablePolynomialAndPolynomialFailingUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  trait TraversablePolynomialAndPolynomialFailingUsage {
    import Lib.TraversablePolynomialModule
    import Lib.PolynomialFailingModule

    val tpm: TraversablePolynomialModule
    val pfm: PolynomialFailingModule

    val tp_pf: pfm.D[Int] ** pfm.D[Int] ** pfm.D[Int] => tpm.D[pfm.D[Int]] = {
      case ((mfmd01, mfmd02), mfmd03) =>
        tpm.one(mfmd01) or tpm.one(mfmd02) or tpm.one(mfmd03)
    }

    lazy val pf_tp: pfm.D[Int] ** pfm.D[Int] ** pfm.D[Int] => pfm.D[tpm.D[Int]] =
      tp_pf andThen tpm.swap(pfm)

    val m1: pfm.mm.M
    val m2: pfm.mm.M

    lazy val example01: pfm.D[Int] ** pfm.D[Int] ** pfm.D[Int] =
      ((pfm.one(1), pfm.one(2)), pfm.one(3))
    lazy val example02: pfm.D[Int] ** pfm.D[Int] ** pfm.D[Int] =
      ((pfm.fail(m1), pfm.one(2)), pfm.one(3))
    lazy val example03: pfm.D[Int] ** pfm.D[Int] ** pfm.D[Int] =
      ((pfm.one(1), pfm.fail(m1)), pfm.fail(m2))

    val tpm_in: tpm.In
    val mfm_in: pfm.In

    def traversablePolynomial_and_multiplicativeFailing_usage() {
      println(tp_pf(example01).run(tpm_in))
      println(pf_tp(example01).run(mfm_in))
      println(tp_pf(example02).run(tpm_in))
      println(pf_tp(example02).run(mfm_in))
      println(tp_pf(example03).run(tpm_in))
      println(pf_tp(example03).run(mfm_in))
    }
  }

Given ZeroOrMore and StringSuccessOrFailure instances it is possible to define

ZeroOrMoreAndStringSuccessOrFailureUsage (ZeroOrMoreAndStringSuccessOrFailureUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  object ZeroOrMoreAndStringSuccessOrFailureUsage
    extends TraversablePolynomialAndPolynomialFailingUsage {
    import Instances.ZeroOrMoreModule
    import Instances.StringSuccessOrFailureModule

    override val tpm: ZeroOrMoreModule.type = ZeroOrMoreModule
    override val pfm: StringSuccessOrFailureModule.type = StringSuccessOrFailureModule

    import pfm.mm._

    override val m1 = StringMonoid("failure1")
    override val m2 = StringMonoid("failure2")

    override val tpm_in = ()
    override val mfm_in = ()
  }

and use it as follows

ZeroOrMoreAndStringSuccessOrFailureUsageInApp (ZeroOrMoreAndStringSuccessOrFailureUsageInApp.scala) download
1
2
3
4
    {
      import Usage.ZeroOrMoreAndStringSuccessOrFailureUsage._
      traversablePolynomial_and_multiplicativeFailing_usage()
    }

Running the examples above would then result in something along the following lines

1
2
3
4
5
6
[ { 1 } { 2 } { 3 } ]
{ [ 1 2 3 ] }
[ { failure1 } { 2 } { 3 } ]
{ failure1 }
[ { 1 } { failure1 } { failure2 } ]
{ failure1 failure2 }

If, as suggested in the code of the actual implementation (not given yet), you comment out the overriding definition of and and make use of the default definition instead, then this results in something along the following lines

1
2
3
4
5
6
[ { 1 } { 2 } { 3 } ]
{ [ 1 2 3 ] }
[ { failure1 } { 2 } { 3 } ]
{ failure1 }
[ { 1 } { failure1 } { failure2 } ]
{ failure1 }

What is the moral of this story:

  • and, being more abstract than bnd, has more implementation flexibility

The default fail fast strategy implementation can (but does not have to) be overridden by a fail slow and accumulate strategy implementation.

Stateful data

Stateful data are formalized by the trait below

Stateful (Stateful.scala) download
1
2
3
4
5
6
7
8
9
  trait StatefulModule {
    type S
    type D[Z] <: Stateful[Z]
    def get: Unit => D[S]
    def set: S => D[Unit]
    def exec: (S => S) => D[Unit]
    trait Stateful[A] {
    }
  }

trait StatefulModule

  • declares a type S
    • S represents state
  • declares the function get
    • get(()) should, somehow, produce the current state
  • declares the function set
    • set(s) should, somehow, set the current state (and produce ())
  • declares the function exec
    • given a function s2s, exec(s2s) should, somehow, transform the current state s to s2s(s) (and produce ())

Stateful data source

Stateful datasources are formalized by the trait below

StatefulSource (StatefulSource.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  trait StatefulSourceModule
    extends SourceModule
    with StatefulModule {
    type D[Z] <: StatefulSource[Z]
    override def exec: (S => S) => D[Unit] =
      s2s =>
        get(()) bnd {
          s =>
            set(s2s(s))
        }
    trait StatefulSource[A]
      extends Source[A]
      with Stateful[A] { da: D[A] =>
    }
  }

trait StatefulSourceModule

  • defines the function exec in terms of get, set and bnd

Stateful datasource usage

The code below defines some example that makes use of the stateful datasource DSL. It deals with a simple “coin and candy” state machine.

StatefulSourceUsage (StatefulSourceUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  trait StatefulSourceUsage {
    import Lib.TraversablePolynomialModule
    val tpm: TraversablePolynomialModule

    import Lib.StatefulSourceModule

    object Status extends Enumeration {
      val FREE, BUSY = Value
    }

    object Action extends Enumeration {
      val COIN_IN, CANDY_OUT = Value
    }

    import Status.{ FREE, BUSY }
    import Action.{ COIN_IN, CANDY_OUT }

    case class Machine(status: Status.Value, candies: Int, coins: Int) {
      def acceptsCoinIn = candies != 0 && status == FREE
      def acceptsCandyOut = candies != 0 && status == BUSY
    }

    val ssm: StatefulSourceModule {
      type S = Machine
      type In = S
      type Out[Z] = S ** Z
    }
    import ssm._

    def executeAction: Action.Value => D[Unit] =
      action => exec {
        machine =>
          action match {
            case COIN_IN if (machine.acceptsCoinIn) =>
              Machine(BUSY, machine.candies, machine.coins + 1)
            case CANDY_OUT if (machine.acceptsCandyOut) =>
              Machine(FREE, machine.candies - 1, machine.coins)
            case _ =>
              machine
          }
      }

    val initialMachine: Machine
    val reducer: tpm.Reducer[Unit, Unit]
    val actions: tpm.D[Action.Value]

    lazy val ss: ssm.D[Unit] =
      actions.foreach(ssm)(executeAction)(reducer)

    def stateful_source_usage() {
      val finalMachine: Machine = ss.run(initialMachine)._1
      println(finalMachine)
    }
  }

The simplest stateful Runnable implementation is the following

StatefulRunnableModule (StatefulRunnableModule.scala) download
1
2
3
4
5
6
7
8
9
10
  trait StatefulRunnableModule
    extends RunnableModule {
    type D[Z] <: StatefulRunnable[Z]
    type S
    type In = S
    type Out[Z] = S ** Z
    trait StatefulRunnable[A]
      extends Runnable[A] { da: D[A] =>
    }
  }

The simplest StatefulSourceModule instance one can think of is one along the following lines

1
2
3
4
5
6
object StateModule {
  // ...
  case class State[A](s_2_sna: S => S ** A) {
  // ...
  }
}

Think of State[Z] as a data source that produces, maintaining state while producing, one value.

Given a State[Z] instance it is possible to define

StateUsage (StateUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  object StateUsage
    extends StatefulSourceUsage {
    import Instances.ZeroOrMoreModule

    override val tpm: ZeroOrMoreModule.type = ZeroOrMoreModule

    import Instances.StateModule

    object MachineStateModule
      extends StateModule {
      type S = Machine
    }

    override val ssm: MachineStateModule.type = MachineStateModule
    import ssm._

    import Status.{ FREE, BUSY }

    override val initialMachine = Machine(FREE, 20, 0)

    import Action.{ COIN_IN, CANDY_OUT }

    import tpm.one

    override val actions: tpm.D[Action.Value] =
      one(COIN_IN) or one(CANDY_OUT) or one(COIN_IN) or one(CANDY_OUT)

    override val reducer: tpm.Reducer[Unit, Unit] =
      ({ case _ => () }, { case (_, _) => () })
  }

and use it as follows

StateUsageInApp (StateUsageInApp.scala) download
1
2
3
4
    {
      import Usage.StateUsage._
      stateful_source_usage()
    }

Running the example above would then result in something along the following lines

1
Machine(FREE,18,2)

Asynchronous data

Asynchronous data are formalized by the trait below

Asynchronous (Asynchronous.scala) download
1
2
3
4
5
6
  trait AsynchronousModule {
    type D[Z] <: Asynchronous[Z]
    def async[Z]: (Unit => Z) => D[Z]
    trait Asynchronous[A] {
    }
  }

trait AsynchronousModule

  • declares the function async
    • given u2z, async(u2z) should produce u2z(()) asynchronously

Asynchronous data source

Asynchronous datasources are declared by the trait below

AsynchronousSource (AsynchronousSource.scala) download
1
2
3
4
5
6
7
8
9
  trait AsynchronousSourceModule
    extends SourceModule
    with AsynchronousModule {
    type D[Z] <: AsynchronousSource[Z]
    trait AsynchronousSource[A]
      extends Source[A]
      with Asynchronous[A] { da: D[A] =>
    }
  }

Asynchronous datasource usage

The code below defines some examples that make use of the asynchronous datasource DSL

AsynchronousSourceUsage (AsynchronousSourceUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  trait AsynchronousSourceUsage {

    import Lib.TraversablePolynomialModule
    import Lib.AsynchronousSourceModule

    val tpm: TraversablePolynomialModule
    import tpm.one
    val asm: AsynchronousSourceModule
    import asm.async

    import java.lang.Thread.sleep

    def sleepVerbose(i: Int): Unit => Int = {
      _ =>
        (1 to 10).toList.foreach {
          x =>
            sleep(500)
            if (x == 10) print(s"\n${i} finished\n")
            else print(s"${i} ")
        }
        i
    }

    import math._

    def randomSleep(timeOut: TimeOut) =
      sleep(round(timeOut * random))

    def randomSleepVerbose(i: Int): Unit => Int = {
      _ =>
        (1 to 10).toList.foreach {
          x =>
            randomSleep(500)
            if (x == 10) print(s"\n${i} finished\n")
            else print(s"${i} ")
        }
        i
    }

    val manySleepVerbose: Int => tpm.D[Unit => Int] =
      n =>
        one(sleepVerbose(n)) or manySleepVerbose(n + 1)

    val manyRandomSleepVerbose: Int => tpm.D[Unit => Int] =
      n =>
        one(randomSleepVerbose(n)) or manyRandomSleepVerbose(n + 1)

    val in: asm.In

    val tp_as01: Int => tpm.D[asm.D[Int]] =
      manySleepVerbose(_) end async take (8)

    lazy val as_tp01: Int => asm.D[tpm.D[Int]] =
      tp_as01 andThen tpm.swap(asm)

    val tp_as02: Int => tpm.D[asm.D[Int]] =
      manyRandomSleepVerbose(_) end async take (8)

    lazy val as_tp02: Int => asm.D[tpm.D[Int]] =
      tp_as02 andThen tpm.swap(asm)

    def asynchronous_source_usage() {
      println(as_tp01(1).run(in))
      println(as_tp02(1).run(in))
    }
  }

The simplest asynchronous Runnable implementation is the following

AsynchronousRunnableModule (AsynchronousRunnableModule.scala) download
1
2
3
4
5
6
7
8
9
  trait AsynchronousRunnableModule
    extends RunnableModule {
    type D[Z] <: AsynchronousRunnable[Z]
    type In = ExecutorService
    type Out[Z] = Z
    trait AsynchronousRunnable[A]
      extends Runnable[A] { da: D[A] =>
    }
  }

The simplest AsynchronousSourceModule instance one can think of is one along the following lines

1
2
3
4
5
6
object AsyncModule {
  // ...
  case class Async[A](es_2_sfa: ExecutorService => SimpleFuture[A]) {
  // ...
  }
}

Think of Async[Z] as a data source that, making use of an executor service, produces one value asynchronously.

Given a Async[Z] instance it is possible to a define

AsyncUsage (AsyncUsage.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  object AsyncUsage
    extends AsynchronousSourceUsage {
    import Instances.ZeroOrMoreModule
    import Instances.AsyncModule

    override val tpm: ZeroOrMoreModule.type = ZeroOrMoreModule
    override val asm: AsyncModule.type = AsyncModule

    import java.util.concurrent.ExecutorService
    import java.util.concurrent.Executors

    override val in: ExecutorService =
      Executors.newScheduledThreadPool(8);

    override def asynchronous_source_usage() {
      super.asynchronous_source_usage
      in.shutdown()
    }

  }

and use it as follows

AsyncUsageInApp (AsyncUsageInApp.scala) download
1
2
3
4
    {
      import Usage.AsyncUsage._
      asynchronous_source_usage()
    }

Running the example above would then result in something along the following lines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2 3 4 1 6 5 7 8 2 6 1 4 8 7 3 5 2 1 6 4 8 7 3 5 2 6 8 7 1 4 3 5 2 6 8 3 4 7 1 5 2 6 3 8 7 1 4 5 2 8 3 6 5 4 1 7 2 8 3 6 1 5 7 4 2 3 8 6 1 5 4 7
3 finished

6 finished

8 finished

2 finished

1 finished

7 finished

5 finished

4 finished
[ 1 2 3 4 5 6 7 8 ]
7 6 6 2 4 8 3 7 1 4 5 6 1 8 3 2 3 8 1 1 6 5 1 7 4 2 2 6 7 1 6 3 8 5 7 2 2 6 4 3 7 3 6 3 8 8 4 1 2 6 5 3
6 finished
7 8 8 5 4 3 1 2
3 finished
5 7 2 8
8 finished
4 1 5 7
2 finished
5 4
1 finished

7 finished
5 4
4 finished

5 finished
[ 1 2 3 4 5 6 7 8 ]

If, as suggested in the code of the actual implementation (not given yet), you comment out the overriding definition of and and make use of the default definition instead, then this results in something along the following lines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1 1 1 1 1 1 1 1 1
1 finished
2 2 2 2 2 2 2 2 2
2 finished
3 3 3 3 3 3 3 3 3
3 finished
4 4 4 4 4 4 4 4 4
4 finished
5 5 5 5 5 5 5 5 5
5 finished
6 6 6 6 6 6 6 6 6
6 finished
7 7 7 7 7 7 7 7 7
7 finished
8 8 8 8 8 8 8 8 8
8 finished
[ 1 2 3 4 5 6 7 8 ]
1 1 1 1 1 1 1 1 1
1 finished
2 2 2 2 2 2 2 2 2
2 finished
3 3 3 3 3 3 3 3 3
3 finished
4 4 4 4 4 4 4 4 4
4 finished
5 5 5 5 5 5 5 5 5
5 finished
6 6 6 6 6 6 6 6 6
6 finished
7 7 7 7 7 7 7 7 7
7 finished
8 8 8 8 8 8 8 8 8
8 finished
[ 1 2 3 4 5 6 7 8 ]

What is the moral of this story:

  • and, being more abstract than bnd, has more implementation flexibility

The default sequential implementation can (but does not have to) be overridden by a concurrent implementation.

Implementations

We still did not fully define any concrete instances yet.

OneModule

OneModule is a TraversableSourceModule

OneModule (OneModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  object OneModule
    extends TraversableSourceModule
    with TrivialRunnableModule {
    type D[Z] = One[Z]
    override def one[Z]: Z => D[Z] =
      z =>
        One(z)
    type Reducer[Z, R] = Z => R
    def identityReducer[Z]: Reducer[Z, D[Z]] =
      one
    override def lift[Z, Y, R](mm: MM)(z2mmdy: Z => mm.D[Y]): Reducer[Y, R] => Reducer[Z, mm.D[R]] = {
      case y2r => {
        val z2mmdr: Z => mm.D[R] = {
          case z =>
            z2mmdy(z) end {
              y =>
                y2r(y)
            }
        }
        z2mmdr
      }
    }
    case class One[A](a: A)
      extends TraversableSource[A]
      with TrivialRunnable[A] { da: D[A] =>
      override def reducedBy[R](a_r2_r: Reducer[A, R]): R = da match {
        case One(a) =>
          a_r2_r match {
            case a2r =>
              a2r(a)
          }
      }
      override def bnd[B](a2db: A => D[B]): D[B] =
        da reducedBy a2db
      override def toString: String = {
        val a2s: A => String = {
          case a =>
            s" ${a}"
        }
        s"{${da reducedBy a2s} }"
      }
    }
  }

ZeroOrOneModule

ZeroOrOneModule is a TraversablePolynomialSourceModule

ZeroOrOneModule (ZeroOrOneModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  object ZeroOrOneModule
    extends TraversablePolynomialSourceModule
    with TrivialRunnableModule {
    type D[Z] = ZeroOrOne[Z]
    override def zero[Z]: Unit => D[Z] =
      _ =>
        Zero()
    override def one[Z]: Z => D[Z] =
      z =>
        One(z)
    type Reducer[Z, R] = (Unit => R) ** (Z => R)
    def identityReducer[Z]: Reducer[Z, D[Z]] =
      (zero, one)
    override def lift[Z, Y, R](mm: MM)(z2mmdy: Z => mm.D[Y]): Reducer[Y, R] => Reducer[Z, mm.D[R]] = {
      case (u2r, y2r) => {
        val u2mmdr: Unit => mm.D[R] = {
          case () =>
            mm.one(u2r(()))
        }
        val z2mmdr: Z => mm.D[R] = {
          case z =>
            z2mmdy(z) end {
              y =>
                y2r(y)
            }
        }
        (u2mmdr, z2mmdr)
      }
    }
    sealed trait ZeroOrOne[A]
      extends TraversablePolynomialSource[A]
      with TrivialRunnable[A] { da: D[A] =>
      override def take(n: Int): D[A] =
        da
      override def reducedBy[R](a_r2_r: Reducer[A, R]): R = da match {
        case Zero() =>
          a_r2_r match {
            case (u2r, _) =>
              u2r(())
          }
        case One(a) =>
          a_r2_r match {
            case (_, a2r) =>
              a2r(a)
          }
      }
      override def bnd[B](a2db: A => D[B]): D[B] =
        da reducedBy (zero[B], a2db)
      override def or(da1: => D[A]): D[A] = {
        val u2da: Unit => D[A] = {
          case () =>
            da1
        }
        val a2da: A => D[A] = {
          case a =>
            one(a)
        }
        da reducedBy (u2da, a2da)
      }
      override def toString: String = {
        val u2s: Unit => String = {
          case () =>
            ""
        }
        val a2s: A => String = {
          case a =>
            s" ${a}"
        }
        s"{${da reducedBy (u2s, a2s)} }"
      }
    }
    private case class Zero[A]() extends ZeroOrOne[A]()
    private case class One[A](a: A) extends ZeroOrOne[A]
  }

ZeroOrMoreModule

ZeroOrMoreModule is a TraversablePolynomialSourceModule

ZeroOrMoreModule (ZeroOrMoreModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  object ZeroOrMoreModule
    extends TraversablePolynomialSourceModule
    with TrivialRunnableModule {
    type D[Z] = ZeroOrMore[Z]
    override def zero[Z]: Unit => D[Z] =
      _ =>
        Zero()
    override def one[Z]: Z => D[Z] =
      z =>
        More((z, zero))
    private def more[Z]: (Z ** (Unit => D[Z])) => D[Z] = {
      case z_n_u2dz =>
        More[Z](z_n_u2dz)
    }
    type Reducer[Z, R] = (Unit => R) ** ((Z ** (Unit => R)) => R)
    def identityReducer[Z]: Reducer[Z, D[Z]] = {
      (zero, more)
    }
    override def lift[Z, Y, R](mm: MM)(z2mmdy: Z => mm.D[Y]): Reducer[Y, R] => Reducer[Z, mm.D[R]] = {
      case (u2r, y_n_u2r__2__r) => {
        val u2mmdr: Unit => mm.D[R] = {
          case () =>
            mm.one(u2r(()))
        }
        val z_n_u2mmdr__2__mmdr: (Z ** (Unit => mm.D[R])) => mm.D[R] = {
          case (z, u2mmdr) =>
            z2mmdy(z) and (
              u2mmdr(()) end {
                r =>
                  y =>
                    y_n_u2r__2__r((y, { case () => r }))
              })

        }
        (u2mmdr, z_n_u2mmdr__2__mmdr)
      }
    }
    sealed trait ZeroOrMore[A]
      extends TraversablePolynomialSource[A]
      with TrivialRunnable[A] { da: D[A] =>
      override def take(n: Int): D[A] =
        da match {
          case Zero() =>
            zero(())
          case More((a, u2da)) =>
            if (n > 0)
              more((a, { case () => u2da(()).take(n - 1) }))
            else
              zero(())
        }
      override def bnd[B](a2db: A => D[B]): D[B] = {
        val a_n_u2db__2__db: (A ** (Unit => D[B])) => D[B] = {
          case (a, u2db) =>
            a2db(a) or u2db(())
        }
        da reducedBy ((zero[B], a_n_u2db__2__db))
      }
      override def or(da1: => D[A]): D[A] = {
        val u2da: Unit => D[A] = {
          case () =>
            da1
        }
        da reducedBy (u2da, more[A])
      }
      override def toString: String = {
        val u2s: Unit => String = {
          case () =>
            ""
        }
        val a_n_u2s__2__s: (A ** (Unit => String)) => String = {
          case (a, s) =>
            s" ${a}${s(())}"
        }
        s"[${da reducedBy (u2s, a_n_u2s__2__s)} ]"
      }
      override def reducedBy[R](a_r2_r: Reducer[A, R]): R =
        da match {
          case Zero() =>
            a_r2_r match {
              case (u2r, _) =>
                u2r(())
            }
          case More((a, u2da)) =>
            a_r2_r match {
              case (u2r, a_n_u2r__2__r) =>
                a_n_u2r__2__r((a, { case () => u2da(()).reducedBy((u2r, a_n_u2r__2__r)) }))
            }
        }
      override def run(in: In): Out[A] =
        da
    }

    private case class Zero[A]() extends ZeroOrMore[A]
    private case class More[A](a_n_u2da: A ** (Unit => D[A])) extends ZeroOrMore[A]
  }

SuccessOrFailureModule

SuccessOrFailureModule is a TraversablePolynomialSourceModule and a PolynomialFailingModule

SuccessOrFailureModule (SuccessOrFailureModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  trait SuccessOrFailureModule
    extends TraversablePolynomialSourceModule
    with PolynomialFailingModule
    with TrivialRunnableModule {
    import mm._
    type D[Z] = SuccessOrFailure[Z]
    override def fail[Z]: M => D[Z] =
      m => Failure(m)
    override def one[Z]: Z => D[Z] =
      z => Success(z)
    type Reducer[Z, R] = (M => R) ** (Z => R)
    override def identityReducer[Z]: Reducer[Z, D[Z]] = {
      (fail, one)
    }
    override def lift[Z, Y, R](mm: MM)(z2mmdy: Z => mm.D[Y]): Reducer[Y, R] => Reducer[Z, mm.D[R]] = {
      case (m2r, y2r) =>
        val m2mmdr: M => mm.D[R] = {
          case m =>
            mm.one(m2r(m))
        }
        val z2mmdr: Z => mm.D[R] = {
          case z =>
            z2mmdy(z) end {
              y =>
                y2r(y)
            }
        }
        (m2mmdr, z2mmdr)
    }
    sealed trait SuccessOrFailure[A]
      extends TraversablePolynomialSource[A]
      with PolynomialFailing[A]
      with TrivialRunnable[A] { da: D[A] =>
      override def take(n: Int): D[A] =
        da
      override def reducedBy[R](a_r2_r: Reducer[A, R]): R = da match {
        case Failure(m) =>
          a_r2_r match {
            case (m2r, _) =>
              m2r(m)
          }
        case Success(a) =>
          a_r2_r match {
            case (_, a2r) =>
              a2r(a)
          }
      }

      override def bnd[B](a2ob: A => D[B]): D[B] = {
        val m2ob: M => D[B] = {
          case m =>
            fail(m)
        }
        val reducer: Reducer[A, D[B]] =
          (m2ob, a2ob)
        da reducedBy reducer
      }
      // comment this one out
      // for
      // fail fast
      // instead of
      // fail slow and accumulate
      override def and[B](d_a2b: => D[A => B]): D[B] = {
        val m2ob: M => D[B] = {
          case m =>
            d_a2b match {
              case Success(_) =>
                fail(m)
              case Failure(m1) =>
                fail(m operator m1)
            }
        }
        val a2ob: A => D[B] = {
          case a =>
            d_a2b match {
              case Success(a2b) =>
                one(a2b(a))
              case Failure(m) =>
                fail(m)
            }
        }
        val reducer: Reducer[A, D[B]] =
          (m2ob, a2ob)
        da reducedBy reducer
      }
      override def or(da1: => D[A]): D[A] = {
        val u2oa: M => D[A] = {
          case m =>
            da match {
              case Success(_) =>
                da
              case Failure(_) =>
                da1
            }
        }
        val a2oa: A => D[A] = {
          case a =>
            one(a)
        }
        val reducer: Reducer[A, D[A]] =
          (u2oa, a2oa)
        da reducedBy reducer
      }
      override def toString: String = {
        val u2s: M => String = {
          case m =>
            s" ${m.toString}"
        }
        val a2s: A => String = {
          case a =>
            s" ${a}"
        }
        val reducer: Reducer[A, String] =
          (u2s, a2s)
        s"{${da reducedBy reducer} }"
      }
      override def run(in: In): Out[A] =
        da
    }
    case class Failure[A](m: M) extends SuccessOrFailure[A]
    case class Success[A](a: A) extends SuccessOrFailure[A]
  }

StateModule

StateModule is a StatefulSourceModule

StateModule (StateModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  trait StateModule
    extends StatefulSourceModule
    with StatefulRunnableModule {
    type D[Z] = State[Z]
    private implicit def toState[Z](s_2_snz: S => S ** Z): D[Z] =
      State(s_2_snz)
    override def one[Z]: Z => D[Z] =
      z => (s: S) => (s, z)
    override def get: Unit => D[S] =
      _ => (s: S) => (s, s)
    override def set: S => D[Unit] =
      s => (_: S) => (s, ())
    case class State[A](s_2_sna: S => S ** A)
      extends StatefulSource[A]
      with StatefulRunnable[A] { da: D[A] =>
      override def bnd[B](a2db: A => D[B]): D[B] =
        (s: S) =>
          da.s_2_sna(s) match {
            case (s1, a) =>
              a2db(a).s_2_sna(s1)
          }
      override def run(s: S): S ** A =
        s_2_sna(s)
    }
  }

AsyncModule

AsyncModule is an AsynchronousSourceModule

AsyncModule (AsyncModule.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  object AsyncModule
    extends AsynchronousSourceModule
    with AsynchronousRunnableModule {
    private implicit def toSimpleFuture[Z](to2z: TimeOut => Z) =
      new SimpleFuture[Z] {
        override def get(timeOut: TimeOut): Z =
          to2z(timeOut)
      }
    private implicit def toAsync[Z](es_2_sfz: ExecutorService => SimpleFuture[Z]) =
      Async(es_2_sfz)
    private implicit def toRunnable(u2u: Unit => Unit) =
      new java.lang.Runnable() { def run() = u2u(()) }
    type D[Z] = Async[Z]
    override def one[Z]: Z => D[Z] =
      z => {
        val es_2_sfz: ExecutorService => SimpleFuture[Z] =
          _ => (_: TimeOut) => z
        es_2_sfz
      }
    override def async[Z]: (Unit => Z) => D[Z] =
      u2z => {
        val es_2_sfz: ExecutorService => SimpleFuture[Z] =
          es => {
            val atomic: Atomic[Z] = new Atomic()
            es.submit {
              (_: Unit) =>
                atomic.setValue(u2z(()))
            }
            (timeOut: TimeOut) => {
              atomic.getValue(timeOut)
            }
          }
        es_2_sfz
      }
    case class Async[A](es_2_sfa: ExecutorService => SimpleFuture[A])
      extends AsynchronousSource[A]
      with AsynchronousRunnable[A] { da: D[A] =>
      override def bnd[B](a2db: A => D[B]): D[B] = {
        val es_2_sfb: ExecutorService => SimpleFuture[B] =
          es => (timeOut: TimeOut) => {
            val startTime = currentTimeMillis()
            val a = es_2_sfa(es).get(timeOut)
            val stopTime = currentTimeMillis()
            (a2db(a)).es_2_sfa(es).get(timeOut - (stopTime - startTime))
          }
        es_2_sfb
      }
      // comment this one out
      // for
      // sequential
      // instead of parallel
      override def and[B](d_a2b: => D[A => B]): D[B] = {
        val es_2_sfb: ExecutorService => SimpleFuture[B] =
          es => {
            val sfa = es_2_sfa(es)
            val sf_a2b = d_a2b.es_2_sfa(es)
            val sfb = (timeOut: TimeOut) => {
              val startTime = currentTimeMillis()
              val a = sfa.get(timeOut)
              val stopTime = currentTimeMillis()
              val a2b = sf_a2b.get(timeOut - (stopTime - startTime))
              a2b(a)
            }
            sfb
          }
        es_2_sfb
      }
      def run(es: ExecutorService): A =
        es_2_sfa(es).get()
    }
  }

AsyncModule makes use of the type TimeOut, the trait SimpleFuture and the class Atomic

TimeOut (TimeOut.scala) download
1
  type TimeOut = Long
SimpleFuture (SimpleFuture.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  trait SimpleFuture[Z]
    extends Future[Z] {
    def get(timeOut: TimeOut): Z
    override def get: Z =
      get(MAX_VALUE)
    override def get(timeOut: TimeOut, timeUnit: TimeUnit): Z =
      get(MILLISECONDS.convert(timeOut, timeUnit))
    override def isDone =
      sys.error("not implemented")
    override def isCancelled =
      sys.error("not implemented")
    override def cancel(interruptable: Boolean) =
      sys.error("not implemented")
  }
Atomic (Atomic.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
  class Atomic[Z] {
    var z: Z = _
    val countDownLatch: CountDownLatch = new CountDownLatch(1)
    def getValue(timeOut: TimeOut) = {
      countDownLatch.await(timeOut, MILLISECONDS)
      z
    }
    def setValue(newZ: Z) {
      z = newZ
      countDownLatch.countDown()
    }
  }

Comments