I'm doing a code review for the Queue3 example in the Programming in Scala 2nd edition by Odersky et al. And I guess i'm stuck.
Here's the code: http://booksites.artima.com/programming_in_scala_2ed/examples/type-parameterization/Queues3.scala
object Queues3 {
class Queue[T](
private val leading: List[T],
private val trailing: List[T]
) {
private def mirror =
if (leading.isEmpty)
new Queue(trailing.reverse, Nil)
else
this
def head = mirror.leading.head
def tail = {
val q = mirror
new Queue(q.leading.tail, q.trailing)
}
def enqueue(x: T) =
new Queue(leading, x :: trailing)
override def toString =
leading ::: trailing.reverse mkString ("Queue(", ", ", ")")
}
object Queue {
// constructs a queue with initial elements `xs'
def apply[T](xs: T*) = new Queue[T](xs.toList, Nil)
}
def main(args: Array[String]) {
val q = Queue[Int]() enqueue 1 enqueue 2
println(q)
}
}
So it's trying to implement a queue in a functional programming way with speed similar to the 开发者_JS百科imperative way.
So to do this it'll split the queue into two part so we can append toward the end by constant speed. The whole queue is basically:
leading ::: trailing.reverse
The book is saying that worst case scenario is when the leading is empty.
So if code do this
val q = Queue[Int]() enqueue 1 enqueue 2
Then, q.leading is List() and q.trailing is List(2,1)
So when I call q.head, the book stated that since leading is empty, mirror will copy everything from trailing, reverse it and set it as leading.
The problem is I don't think this work because it's a method? So it doesn't persist via state. Because I made the code properties public and checked q.leading and q.trailing and the value is the same. What I'm expecting after I do q.head is:
q.leading is List(1,2) and q.trailing is List()
But it is not, am I missing something? Is this some FP paradigm that I'm missing? Because I think it can work the way I think it should work if head and tail methods is change to var.
Thank you for your time.
Edit making the properties public:
private val leading: List[T],
private val trailing: List[T]
edit: chapter 19 in 1st edition: http://www.artima.com/pins1ed/type-parameterization.html
You problem is that head
and tail
methods doesn't return new Queue
. And you are inspecting the old one. Checkout this versions of head
and tail
. Now they return new Queue
in a tuple.
def head: (T, Queue[T]) = {
val q = mirror
(q.leading.head, q)
}
def tail: (Queue[T], Queue[T]) = {
val q = mirror
(new Queue(q.leading.tail, q.trailing), q)
}
As you can see, mirror
works fine.
val q = Queue[Int]() enqueue 1 enqueue 2
println(q)
printLT(q)
val q1 = q.head
println(q1._1)
printLT(q1._2)
def printLT[A](q: Queue[A]) {
println("leading: " + q.leading)
println("trailing: " + q.trailing)
}
Output:
Queue(1, 2)
leading: List()
trailing: List(2, 1)
1
leading: List(1, 2)
trailing: List()
精彩评论