【发布时间】:2014-04-12 13:56:39
【问题描述】:
我正在尝试通过实现我自己的惰性列表版本来学习如何使用 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 之外,我已经能够实现它们。我对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 使其适用于无限列表?
【问题讨论】:
标签: scala lazy-evaluation