【问题标题】:How can this Stream iterate-takeWhile code be rewritten without side effects?如何在没有副作用的情况下重写这个 Stream iterate-takeWhile 代码?
【发布时间】:2019-10-03 14:51:48
【问题描述】:

我在 Scala 2.12.x 中编写了一个小型网站 Google 排名检查器,它使用页面抓取来查找给定搜索词的网站排名。我想使用 Scala 的 Stream 构建它,这是代码的控制结构模拟。但是,我找不到没有副作用的方法来重写它,换句话说,不使用任何var

def main(args: Array[String]): Unit = {
  val target = 22 // normally this would be the website domain name
  val inf = 100   // we don't care for ranks above this value
  var result: Option[Int] = None // <============= Side effects! how to rewrite it?
  Stream.iterate(0)(_ + 10).takeWhile { i =>
    // assume I'm page-scraping Google with 10 results per page
    // and need to find the rank or position where the target
    // website appears
    for (j <- i until (i + 10)) {
      // check whether the website was found
      if (j == target) {
        result = Some(j)         // <============= Side effects! how to rewrite it?
      }
    }
    result.isEmpty && i < inf
  }.toList
  println(result.getOrElse(inf))
}

基本上我希望Stream 语句直接返回result,这是目标网站出现的位置或排​​名。我无法逐个迭代,因为代码一次获取 10 个结果的每一页,对它们进行页面抓取并在每组 10 个结果中搜索目标网站。

【问题讨论】:

    标签: scala functional-programming stream side-effects


    【解决方案1】:

    您可以将管道拆分为mapdropWhile(替换为takeWhile):

    val target = 22 // normally this would be the website domain name
    val inf = 100   // we don't care for ranks above this value
    
    val result = Stream.iterate(0)(_ + 10).map { i => 
      //or maybe just use find?
       val r = Stream.range(i-10, i).dropWhile(_ != target).headOption 
      (r,i) //we pass result with index for dropWhile
    }.dropWhile{
      case (r, i) => r.isEmpty && i < inf //drop while predicate is false
    }.map(_._1) //take only result
      .head //this will throw an exception if nothing is found, maybe use headOption?
    

    您还应该知道,我只是摆脱了分配可变变量,但您的代码仍然会产生副作用,因为您正在进行网络调用。

    您应该考虑使用Future 或某种IO monad 来处理这些调用。

    【讨论】:

    • 感谢您的精彩回答!是的,我的意思是副作用专门使用vars,但你是对的!我一定会使用Future 好的提示!我的计划是稍后将此解决方案插入 Akka ......现在只是一个原型。
    猜你喜欢
    • 2019-10-03
    • 1970-01-01
    • 2018-12-17
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多