练习scala Stream类和理论解释

时间:2015-03-07 19:15:38

标签: scala stream lazy-evaluation

我正在对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)函数的代码需要或者至少有一些提示可以自己编写。

1 个答案:

答案 0 :(得分:0)

实现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




}