code

2016年11月11日 星期五

Scala筆記 23 - 用for做random value generator

用trait做random value generator

這是常見的一種架構,先定義一個trait:


trait Generator[T] {
  def generate : T}

然後藉由實做這個trait得出各種不同type的random value generators:


val integers = new Generator[Int] {
  override def generate: Int = new Random().nextInt()
}

val booleans = new Generator[Boolean] {
  override def generate: Boolean = integers.generate > 0}

val pairs = new Generator[(Int,Int)] {
  override def generate: (Int, Int) = (integers.generate, integers.generate)
}

這樣定義ok, 但是使用上很麻煩,每次延伸一個新的種類,都要new一個generator出來,能不能不要用這種方式呢? 


嘗試用for試試看

我們希望達到的類似這樣的架構來定義新的種類的generators (所以for statment中的generators不限於collection type, 而是某個有implement map的object都可):


根據我們之前在解讀for的筆記中知道,compiler會把以上的for statement解譯成以下:


所以我們只要幫我們的random generator 實作map, flatmap就可以用for來使用。

我們的Generator trait新增了兩個 methods:

trait Generator[T] {
  self => //相當於 Generator.this

  def generate : T //產生random value
  //回傳一個Generator[S],  
//generate的定義為把self產生的random value經過f mapping  def map[S](f:T => S):Generator[S] = new Generator[S] {
    override def generate: S = f(self.generate)
  }

  //回傳一個Generator[S],  
//generate的定義為把self產生的random value經過f map Generator[S]instance  
//然後回傳此generatorgenerate method  
def flatMap[S](f: T => Generator[S]): Generator[S] = new Generator[S] {
    def generate : S = f(self.generate).generate
  }

}


如何解讀新的Generator?

如果用這個Generator trait的定義來實作booleans的隨機產生器的話,可以看到以下的substitution steps:


所以booleans被替換成跟我們在上一段的寫法一樣。

why all the efforts?!


解讀用for定義pairs的generator:


好難懂!!!!! 以後有遇到需求再回來研究吧!


沒有留言:

張貼留言