加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何在递归上下文中解释延迟?

发布时间:2020-12-16 18:06:42 所属栏目:安全 来源:网络整理
导读:这是 FPIS的代码 object test2 { //a naive IO monad sealed trait IO[A] { self = def run: A def map[B](f: A = B): IO[B] = new IO[B] { def run = f(self.run) } def flatMap[B](f: A = IO[B]): IO[B] = { println("calling IO.flatMap") new IO[B] { de
这是 FPIS的代码

object test2 {

  //a naive IO monad
  sealed trait IO[A] { self =>
    def run: A
    def map[B](f: A => B): IO[B] = new IO[B] { def run = f(self.run) }
    def flatMap[B](f: A => IO[B]): IO[B] = {
      println("calling IO.flatMap")
      new IO[B] {
        def run = {
            println("calling run from flatMap result")
            f(self.run).run
        }
     }
    }
  }

  object IO {
    def unit[A](a: => A): IO[A] = new IO[A] { def run = a }
    def apply[A](a: => A): IO[A] = unit(a) // syntax for IO { .. }
  }

  //composer in question
  def forever[A,B](a: IO[A]): IO[B] = {
    lazy val t: IO[B] = a flatMap (_ => t)
    t
  }

  def PrintLine(msg: String) = IO { println(msg) }

  def say = forever(PrintLine("Still Going..")).run
}

在堆栈溢出之前,test2.say将打印数千个“Still Going”.但我不确切知道这是怎么发生的.

输出如下所示:
阶> test2.say
只调用IO.flatMap //一次
从flatMap结果调用run
仍在继续..
从flatMap结果调用run
仍在继续..

… //重复直到堆栈溢出

当函数永远返回时,懒惰的val是否被完全计算(缓存)?
并且,flatMap方法似乎只被调用一次(我添加了print语句),它反对永远的递归定义.为什么?

===========
我觉得有趣的另一件事是永远[A,B]中的B型可能是任何东西. Scala实际上可以运行,因为它是不透明的.

我手动尝试永远[单位,双],永远[单位,字符串]等,这一切都有效.这感觉很聪明.

解决方法

I’d like to know when function forever returns,is the lazy val t fully computed (cached)?

If so then why need the lazy keyword?

在你的情况下没用.在以下情况下它可能很有用:

def repeat(n: Int): Seq[Int] {
  lazy val expensive = "some expensive computation"
  Seq.fill(n)(expensive)
  // when n == 0,the 'expensive' computation will be skipped
  // when n > 1,the 'expensive' computation will only be computed once
}

The other thing I don’t understand is that the flatMap method seems to
be called only once (I add print statements) which counters the
recursive definition of forever. Why?

在您提供最小,完整和可验证的示例之前无法发表评论,例如@Yuval Itzchakov说

更新时间2017/04/19

好吧,我需要纠正自己:-)在你的情况下,由于递归引用回到自身,所以需要lazy val.

为了解释你的观察,让我们尝试扩展forever(a).run调用:

>永远(a)扩展到
> {lazy val t = flatMap(_ => t)}扩展为
> {lazy val t = new IO [B] {def run()= {… t.run}}

因为t是惰性的,所以2和3中的flatMap和新IO [B]只被调用一次,然后“缓存”以便重用.

在3上调用run()时,你会在t.run上开始递归,从而得到你观察到的结果.

不完全确定您的要求,但永远的非堆栈版本可以实现如下:

def forever[A,B](a: IO[A]): IO[B] = {
    new IO[B] {
      @tailrec
      override def run: B = {
        a.run
        run
      }
    }
  }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读