关于scala Stream类的练习和理论解释



我正在做一个关于scala流的练习。我从书中得到了以下代码。(我写了toList函数)

  trait Stream2[+A] {
    def uncons: Option[(A, Stream2[A])]
    def isEmpty: Boolean = uncons.isEmpty
        def toList: List[A] = {
            def toListAcc(l:List[A], s:Stream2[A]):List[A]= {
                s.uncons match {
                    case Some((h, t)) => toListAcc(List(h) ++ l, t)
                    case None => l
                }
            }
            toListAcc(List(), this).reverse
        }

        def take(n: Int): Stream[A] = {
             ???}
  }
  object Stream2 {
    def empty[A]: Stream2[A] =
      new Stream2[A] { def uncons = None }
    def cons[A](hd: => A, tl: => Stream2[A]): Stream2[A] =
      new Stream2[A] {
        lazy val uncons = Some((hd, tl))
      }
    def apply[A](as: A*): Stream2[A] =
      if (as.isEmpty) empty
      else cons(as.head, apply(as.tail: _*))

  }

  val s = Stream2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  //> s  : chapter5.Stream2[Int] = chapter5$$anonfun$main$1$Stream2$3$$anon$2@782a
                                                  //| fee5
  s.toList                                        //> res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

  }

现在,我必须编写take函数,该函数创建一个只有前n个元素的流。我完全迷失了方向,不知道该怎么办。我认为我的问题是因为我没有完全理解Stream2对象是如何创建的。我想这与uncons函数(或者可能是cons)有关。

所以最后我想:

1) 解释这个代码应该如何工作

2) 要知道toList是否在延迟评估拨号方式方面写得正确

3) 该函数的代码需要或至少需要一些提示才能自己编写。

一个可能的解决方案,实现take和其他一些函数。代码仍然很粗鲁,因此更好的答案是欢迎

object chapter5 {
  println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet
  trait Stream2[+A] {
    def uncons: Option[(A, Stream2[A])]
    def isEmpty: Boolean = uncons.isEmpty
    def toList: List[A] = {
      def toListAcc(l: List[A], s: Stream2[A]): List[A] = {
        s.uncons match {
          case Some((h, t)) => toListAcc(List(h) ++ l, t)
          case None         => l
        }
      }
      toListAcc(List(), this).reverse
    }
    def take(n: Int): Stream2[A] = {
      def takeAcc(n: Int, s: Stream2[A], acc: Stream2[A]): Stream2[A] =
        {
          if (n == 0) acc
          else {
            s.uncons match {
              case Some((h, t)) => takeAcc(n - 1, t, Stream2.cons(h, acc))
              case None         => acc
            }
          }
        }
      val sReverse = takeAcc(n, this, Stream2())
      takeAcc(n, sReverse, Stream2())
    }
    def foldRight[B](z: => B)(f: (A, => B) => B): B =
      uncons match {
        case Some((h, t)) => f(h, t.foldRight(z)(f))
        case None         => z
      }
    def exists(p: A => Boolean): Boolean =
      foldRight(false)((a, b) => p(a) || b)
    def map[B](f: A => B): Stream2[B] = {
      foldRight(Stream2[B]())((x, y) => Stream2.cons(f(x), y))
    }
        def forAll(p: A => Boolean): Boolean = {
            foldRight(true)((x, y) =>  p(x) && y)
        }
  }
  // end of trait
  object Stream2 {
    def empty[A]: Stream2[A] =
      new Stream2[A] { def uncons = None }
    def cons[A](hd: => A, tl: => Stream2[A]): Stream2[A] =
      new Stream2[A] {
        lazy val uncons = Some((hd, tl))
      }
    def apply[A](as: A*): Stream2[A] =
      if (as.isEmpty) empty
      else cons(as.head, apply(as.tail: _*))
  }
  //end of obj Stream2
  val s = Stream2(1, 2, 3, 4)                     //> s  : chapter5.Stream2[Int] = chapter5$$anonfun$main$1$Stream2$3$$anon$2@70c
                                                  //| 73be3
  s.toList                                        //> res0: List[Int] = List(1, 2, 3, 4)
  Stream2.cons(0, s).toList                       //> res1: List[Int] = List(0, 1, 2, 3, 4)
  s.take(5).toList                                //> res2: List[Int] = List(1, 2, 3, 4)
  s.foldRight(0)((x, y) => x + y)                 //> res3: Int = 10
    s.map(x=>x*x).toList                      //> res4: List[Int] = List(1, 4, 9, 16)
    s.forAll(x=>x%2==0)                       //> res5: Boolean = false
    s.forAll(x=> x>0)                         //> res6: Boolean = true


}

相关内容

  • 没有找到相关文章

最新更新