reactive programming 1.4 Functional Random Generators

 只有collection是可以用for表示式吗? 不是的,任何实现了map, flatMap, filter的类都可以



1.整数生成器


package week2

trait Generator[+T] {
  def generate: T
}
object Test extends App {

  val integers = new Generator[Int] {
    val random = new java.util.Random()
    def generate = random.nextInt()
  }
  print (integers.generate)
}

2.布尔值生成器

  val bools = new Generator[Boolean] {
    def generate =  integers.generate > 0
  }
  for (i <- 1 to 10)  println (bools.generate)

3. Pair生成器

  val pairs = new Generator[(Int, Int)] {
    def generate = (integers.generate, integers.generate)
  }
  
  for (i <- 1 to 10)  println (pairs.generate)

4. 能不能更简洁些,每次都用 new Generator很麻烦

如果能这样岂不很好

  val booleans = for (x <- integers) yield x > 0
  def pairs[T, U](t: Generator[T], u: Generator[U]) = for {
    x <- t
    y <- u
  } yield (x, y)

通过上节我们知道for循环没翻译成map,flatMat,filter来执行,要想在for循环中用integers就得定义map方法

package week1

trait Generator[+T] {
  self =>
  def generate:T
  def map[S](f: T => S): Generator[S] = new Generator[S] {
    def generate = f(self.generate)
  }
}

测试

package week1

object Test {
  println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet
  val Integers = new Generator[Int] {
    val rand = new java.util.Random
    def generate = rand.nextInt()
  }                                               //> Integers  : week1.Generator[Int]{val rand: java.util.Random} = week1.Test$$a
                                                  //| nonfun$main$1$$anon$1@693ba66d
  val Bools = for {x <- Integers} yield x > 0     //> Bools  : week1.Generator[Boolean] = week1.Generator$$anon$1@498665a0
  Bools.generate                                  //> res0: Boolean = true
}

实现flatMap方法,这个有点抽象,我们先回忆一下for语句的展开规则

for (x <- e1) yield e2
// 被展开成
e1.map(x => e2)


for (x <- e1; y <- e2 ) yield e3
// 被展开成
e1.flatMap(x => for (y <- e2) yield e3)
// 进一步被展开成
e1.flatMap(x => e2.map(y => e3))

我们的目标是:

  def pairs[T, U](t: Generator[T], u: Generator[U]) = for {
    x <- t
    y <- u
  } yield (x, y)
  
  // 会被展开成
  
  t.flatMap(x => u.map(y => (x, y)))
  //进而
  t.flatMap(x => new Generator[U] { def generate = (x, self.generate(y))})

那么flatMap应该做些什么呢?

将x替换成 T.this.generate(x), 交给参数

package week1

trait Generator[+T] {
  self =>
  def generate:T
  def map[S](f: T => S): Generator[S] = new Generator[S] {
    def generate = f(self.generate)
  }
  
  def flatMap[S](f: T => Generator[S]): Generator[S] = new Generator[S] {
    def generate = f(self.generate).generate
  }
}

测试

package week1

object Test {
  println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet
  val Integers = new Generator[Int] {
    val rand = new java.util.Random
    def generate = rand.nextInt()
  }                                               //> Integers  : week1.Generator[Int]{val rand: java.util.Random} = week1.Test$$a
                                                  //| nonfun$main$1$$anon$1@33b93f89
  val Bools = for {x <- Integers} yield x > 0     //> Bools  : week1.Generator[Boolean] = week1.Generator$$anon$1@6f55137
  Bools.generate                                  //> res0: Boolean = true
  
  val  Pairs = for (x <- Integers; y <- Bools) yield (x, y)
                                                  //> Pairs  : week1.Generator[(Int, Boolean)] = week1.Generator$$anon$2@bcb4598
   Pairs.generate                                 //> res1: (Int, Boolean) = (-918487409,true)
  
}


你可能感兴趣的:(scala)