2012-05-04 17 views
6

Tôi hiện đang học Scala bằng cách làm việc thông qua cuốn sách "Lập trình trong Scala". Cho đến nay, đã có lời giải thích tốt đẹp cho tất cả mọi thứ có vẻ lạ (từ góc nhìn của một lập trình viên Java), nhưng đây là một ví dụ sử dụng một Stream để tạo ra các dãy Fibonacci lá tôi loại bối rối:Làm thế nào là khuyết điểm của Stream :: được dịch ở Scala?

def fibFrom(a: Int, b: Int): Stream[Int] = 
    a #:: fibFrom(b, a + b) 

Làm thế nào là xây dựng của luồng được thực hiện? Tất nhiên các nhà điều hành #:: là bằng cách nào đó chịu trách nhiệm về điều đó. Tôi hiểu rằng kể từ khi nó kết thúc vào :, nó là kết hợp đúng, nhưng điều đó không giải thích việc tạo Luồng. Tôi đoán nó được ngầm dịch sang một nhà xây dựng bằng cách nào đó nhưng tôi không thấy tại sao và chính xác như thế nào.

Tôi đã tìm câu trả lời trong Predef.scalaLowPriorityImplicits.scala nhưng không may mắn cho đến thời điểm này.

Ai đó có thể khai sáng cho tôi không?

Trả lời

8

Đó là kết hợp đúng để nó hoạt động như một phương pháp trên lập luận đúng:

fibFrom(b, a + b).#::(a) 

Ít nhất đó là những gì nó cố gắng để làm cú pháp. Stream[Int] không có phương thức như vậy. May mắn thay, object Stream có ẩn đối với một số lớp học ConsWrapper có phương pháp này (code).

Vì vậy, những gì bạn nhận được sau khi giải quyết ngầm là thế này:

immutable.this.Stream.consWrapper(fibFrom(b, a + b)).#::(a) 
+0

Cảm ơn, đúng vậy. Tôi quên rằng chuyển đổi tiềm ẩn cũng có thể được xác định trong đối tượng đồng hành của lớp cần được chuyển đổi. – rolve

+5

Scaladoc có lẽ sẽ tự động bao gồm những người bạn đồng hành mã hóa cứng. – Debilski

+2

Có thể chỉ ra những người khác mới đến Scala rằng nó không phải là _just_ rằng nó là đúng liên kết. Nó cũng là ConsWrapper thực hiện '# ::' như [call-by-name] (https://github.com/scala/scala/blob/v2.10.3/src/library/scala/collection/immutable/Stream. scala # L1042). tức là '⇒' trong' ConsWrapper (tl: ⇒ Stream [A]) 'sao cho bản dịch thành' immutable.this.Stream.consWrapper (fibFrom (b, a + b)). #: :(a) 'có nghĩa là 'fibFrom (b, a + b)' sẽ chỉ được gọi khi được truy cập. – nicerobot

2

A Stream cũng tương tự như một danh sách. Nó chỉ biết phần đầu của nó và phần còn lại của luồng: Stream (đầu: T, tail: Stream [T]). Sự khác biệt là, luồng được đánh giá uể oải. Dấu ':' ở cuối tên của phương thức nói rằng phương thức này là kết hợp đúng. Vì vậy, biểu thứC# :: fibFrom (b, a + b) được dịch (bởi trình biên dịch) thành fibFrom (b, a + b). #: :(a).

+0

Cảm ơn, đó là những gì tôi đã tìm, nhưng nó không giải thích cách tạo đối tượng Stream. Nếu Stream có một phương thức '# ::', điều này sẽ gây ra một đệ quy vô hạn mà tôi đoán. – rolve

+0

# :: giống như :: trong Danh sách. Và có nó là một đệ quy vô hạn. Bạn chỉ cần lấy số lượng các yếu tố bạn muốn. Đó là những gì tôi muốn thể hiện bằng cách nói rằng nó được đánh giá một cách lười biếng. Điều này có nghĩa là nó sẽ được tính toán khi có nhu cầu về máy tính. –

+0

Nó không hoàn toàn giống nhau, không. Nếu nó giống nhau, bạn sẽ có một đệ quy vô hạn ở đó. Thay vào đó, '# ::' (được định nghĩa trong Class 'ConsWrapper', không phải Stream!) Có tham số by-name được đánh giá là lazily. – rolve

Các vấn đề liên quan