当使用来自scalaz-stream的`halt`时,对于'Yye`组合器的副作用

时间:2015-11-10 08:44:01

标签: scalaz scalaz-stream

filter(内部使用halt)终止其他分支,即使它有一些副作用:

scala> val p = Process("1","2", "3")
scala> val p1 = p.filter(_ => true).map(_ + "p1").observe(io.stdOutLines)
scala> val p2 = p.filter(_ => false).map(_ + "p2").observe(io.stdOutLines)
scala> (p1 yip p2).run.run
1p1

scala> val p2 = p.filter(_ => true).map(_ + "p1").observe(io.stdOutLines)
scala> (p1 yip p2).run.run
1p1
1p2
2p1
2p2
3p1
3p2

似乎是合乎逻辑的,因为在yip之后没有值返回filter。但是用observe指定的副作用呢?

我目前的解决方案是使用flatMap指定默认值:

scala> val p1 = p.map(_ + "p1").flatMap(x => Process.emit(x).observe(io.stdOutLines))

scala> val p2 = p.map(_ + "p2").flatMap(x => Process.emit(""))

scala> (p1 yip p2).run.run
1p1
2p1
3p1

但也许有办法使用filter

P.S。 merge组合器为其他分支执行副作用(因为它不需要返回值),但如果一个停止,它不会等待其他分支(即使它有副作用)。

2 个答案:

答案 0 :(得分:0)

即使在p2终止后也要运行效果,需要明确default行为。所以可能有这些解决方案:

  1. 定义p2以在终止后提供默认值
  2. 如果我们真的不需要元组,请使用either Wye左转和权利
  3. 或许(1)更接近问题,代码看起来像:

    val p = Process("1","2", "3")
    val p1 = p.filter(_ => true).map(_ + "p1").observe(io.stdOutLines)
    val p2 = p.filter(_ => false).map(_ + "p2")
             .observe(io.stdOutLines).map(Some(_)) ++ emit(None).repeat
    // alternativelly
    // val p2 = p.map { v =>  if (pred(v)) right(v) else left(v) }
    //          .observeO(o.stdOutLines).flatMap { _.toOption }
    //          ++ emit(None).repeat             
    
    (p1 yip p2).run.run
    

答案 1 :(得分:0)

实际上它应该是这样的:

in.map(emit).flatMap{ p =>
  val p1 = p.map(_ + "p1").filter(_ => true).observe(out)
  val p2 = p.map(_ + "p2").filter(_ => false).observe(out)
  p1 merge p2
}.run.run

它会使所有副作用井井有条,因为filter不能获得多于​​一个值(由发射产生)