red String 'Result'"
5 } yield c + (a * b).shows //> res7: scalaz.WriterT[scalaz.Id.Id,String,String] = WriterT((Entered Int 3 En 6 //| tered Int 4 Entered String 'Result',Result:12))
如果A是高阶类型如List[T]的话,还能使用吗:
1 for {
2 la <- List(1,2,3) set Vector("Entered List(1,2,3)")
3 lb <- List(4,5) set Vector("Entered List(4,5)")
4 lc <- List(6) set Vector("Entered List(6)")
5 } yield (la |@| lb |@| lc) {_ + _ + _} //> res1: scalaz.WriterT[scalaz.Id.Id,scala.collection.immutable.Vector[String]
6 //| ,List[Int]] = WriterT((Vector(Entered List(1,2,3), Entered List(4,5), Enter
7 //| ed List(6)),List(11, 12, 12, 13, 13, 14)))
的确没有问题。
那个gcd例子还是挺有代表性的,我们用Writer来运算和跟踪gcd运算:
1 def gcd(a: Int, b: Int): Writer[Vector[String],Int] =
2 if (b == 0 ) for { 3 _ <- Vector("Finished at "+a.shows).tell 4 } yield a 5 else
6 Vector(a.shows+" mod "+b.shows+" = "+(a % b).shows).tell >>= {_ => gcd(b,a % b)} 7 //> gcd: (a: Int, b: Int)scalaz.Writer[Vector[String],Int]
8
9 gcd(8,3) //> res8: scalaz.Writer[Vector[String],Int] = WriterT((Vector(8 mod 3 = 2, 3 mo 10 //| d 2 = 1, 2 mod 1 = 0, Finished at 1),1))
11 gcd(16,4) //> res9: scalaz.Writer[Vector[String],Int] = WriterT((Vector(16 mod 4 = 0, Fin 12 //| ished at 4),4))
在维护跟踪记录(logging)时使用Vector会比List更高效。我们来证明一下:
1 def listLogCount(c: Int): Writer[List[String],Unit] = { 2 @annotation.tailrec 3 def countDown(c: Int, w: Writer[List[String],Unit]): Writer[List[String],Unit] = c match { 4 case 0 => w >>= {_ => List("0").tell } 5 case x => countDown(x-1, w >>= {_ => List(x.shows).tell }) 6 } 7 val t0 = System.currentTimeMillis 8 val r = countDown(c,List[String]().tell) 9 val t1 = System.currentTimeMillis 10 r >>= {_ => List((t1 -t0).shows+"msec").tell } 11 } //> listLogCount: (c: Int)scalaz.Writer[List[String],Unit]
12 def vectorLogCount(c: Int): Writer[Vector[String],Unit] = { 13 @annotation.tailrec 14 def countDown(c: Int, w: Writer[Vector[String],Unit]): Writer[Vector[String],Unit] = c match { 15 case 0 => w >>= {_ => Vector("0").tell } 16 case x => countDown(x-1, w >>= {_ => Vector(x.shows).tell }) 17 } 18 val t0 = System.currentTimeMillis 19 val r = countDown(c,Vector[String]().tell) 20 val t1 = System.currentTimeMillis 21 r >>= {_ => Vector((t1 -t0).shows+"msec").tell } 22 } //> vectorLogCount: (c: Int)scalaz.Writer[Vector[String],Unit]
23
24 (listLogCount(10000).run)._1.last //> res10: String = 361msec
25 (vectorLogCount(10000).run)._1.last //> res11: String = 49msec
看,listLogCount(10000)用了361msec
vectorLogCount(10000)只用了49msec,快了8,9倍呢。
|