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

Lazy val在Scala中实现惰性列表

发布时间:2020-12-16 18:51:46 所属栏目:安全 来源:网络整理
导读:我正在尝试通过实现我自己的懒惰列表版本来学习如何在 Scala中使用内置的懒惰: object LazyList { def empty[A] : LazyList[A] = new LazyList[A] { lazy val uncons = None } def cons[A](h : = A,t : = LazyList[A]) : LazyList[A] = new LazyList[A] { l
我正在尝试通过实现我自己的懒惰列表版本来学习如何在 Scala中使用内置的懒惰:

object LazyList {

  def empty[A] : LazyList[A] = new LazyList[A] {
    lazy val uncons = None
  }

  def cons[A](h : => A,t : => LazyList[A]) : LazyList[A] = new LazyList[A] {
    lazy val uncons = Some( (h,t) )
  }

  def from(s : Int) : LazyList[Int] = new LazyList[Int] {
    lazy val uncons = Some( (s,from(s + 1)) )
  }
}

trait LazyList[A] {

  import LazyList._

  def uncons : Option[(A,LazyList[A])]

  def fmap[B](f : A => B) : LazyList[B] = uncons match {
    case None          => empty
    case Some( (h,t) ) => cons(f(h),t.fmap(f))
  }

  def take(i : Int) : LazyList[A] = uncons match {
    case None          => empty
    case Some( (h,t) ) => if (i <= 0) empty else cons(h,t.take(i - 1))
  }

  override def toString : String = uncons match {
    case None          => "[]"
    case Some( (h,t) ) => "[" ++ h.toString ++ ",..]"
  }
}

这似乎有效,我可以,例如,将{_ 2}映射到无限列表:

> LazyList from 1 fmap { _ + 2 }
res1: LazyList[Int] = [2,..]

我决定实现一些我经常使用的函数,比如drop,take等,我已经能够实现它们,除了inits.我的实现是:

def inits : LazyList[LazyList[A]] = uncons match {
    case None          => empty
    case Some( (h,t) ) => cons(empty,t.inits.fmap(cons(h,_)))
  }

问题是由于某种原因它无法在无限列表上工作.例如,我不能写:

> LazyList from 1 inits

因为它永远运行在t.inits之后,问题似乎是fmap,由于某种原因,打破了懒惰(如果我删除fmap它是错误的但是懒惰).为什么fmap强制执行严格性,并且根据我的类型LazyList,如何实现inits以使其在无限列表上工作?

解决方法

fmap和inits在调用时都会剥离一个实际(非惰性)元素;他们都是uncons.由于它们互相调用,因此链永远不会终止于无限的LazyList.

具体来说,请注意uncons不返回a => LazyList但是实际的LazyList,所以当你调用时

Some( (h,t) )

评估t.如果对t的评估称为uncons,那么它也将评估并且您将进入堆栈溢出竞争.这里注意到这一点很棘手,因为它是双递归.

你需要让其中一个剥离零拷贝.你可以做到这一点的一种方法是使uncons元组的第二个参数变为惰性(显式地,通过使其成为Function0):

object LazyList {
  def empty[A]: LazyList[A] = new LazyList[A] {
    lazy val uncons = None
  }

  def cons[A](h: => A,t: => LazyList[A]) : LazyList[A] = new LazyList[A] {
    lazy val uncons = Some( (h,() => t) )
  }

  def from(s: Int): LazyList[Int] = new LazyList[Int] {
    lazy val uncons = Some( (s,() => from(s + 1)) )
  }
}

trait LazyList[A] {
  import LazyList._

  def uncons: Option[(A,() => LazyList[A])]

  def fmap[B](f: A => B): LazyList[B] = uncons match {
    case None          => empty
    case Some( (h,t().fmap(f))
  }

  def take(i: Int): LazyList[A] = uncons match {
    case None          => empty
    case Some( (h,t().take(i - 1))
  }

  override def toString: String = uncons match {
    case None          => "[]"
    case Some( (h,..]"
  }
}

然后你的实现工作:

def inits: LazyList[LazyList[A]] = uncons match {
    case None          => empty
    case Some( (h,t().inits.fmap(cons(h,_)))
  }

拥有这样做的内部解构器以及适合尾巴的外向解构器可能更好.

(编辑:李大同)

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

    推荐文章
      热点阅读