Vì vậy, tôi đang làm việc để tự dạy mình Scala, và một trong những thứ tôi đã chơi với là lớp Stream
. Tôi cố gắng để sử dụng một dịch ngây thơ của classic Haskell version of Dijkstra's solution cho vấn đề số Hamming:Kết hợp mẫu và các dòng vô hạn
object LazyHammingBad {
private def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
(a, b) match {
case (x #:: xs, y #:: ys) =>
if (x < y) x #:: merge(xs, b)
else if (y < x) y #:: merge(a, ys)
else x #:: merge(xs, ys)
}
val numbers: Stream[BigInt] =
1 #:: merge(numbers map { _ * 2 },
merge(numbers map { _ * 3 }, numbers map { _ * 5 }))
}
Lấy này cho một spin trong người phiên dịch đã dẫn một cách nhanh chóng để sự thất vọng:
scala> LazyHammingBad.numbers.take(10).toList
java.lang.StackOverflowError
tôi quyết định xem xét để xem nếu những người khác đã giải quyết vấn đề ở Scala bằng cách sử dụng phương pháp tiếp cận Haskell và điều chỉnh this solution từ Mã Rosetta:
object LazyHammingGood {
private def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
if (a.head < b.head) a.head #:: merge(a.tail, b)
else if (b.head < a.head) b.head #:: merge(a, b.tail)
else a.head #:: merge(a.tail, b.tail)
val numbers: Stream[BigInt] =
1 #:: merge(numbers map {_ * 2},
merge(numbers map {_ * 3}, numbers map {_ * 5}))
}
Điều này làm việc độc đáo, nhưng tôi vẫn tự hỏi làm thế nào tôi đã đi sai trong LazyHammingBad
. Việc sử dụng #::
để hủy cấu trúc x #:: xs
có buộc phải đánh giá xs
vì một số lý do không? Có cách nào để sử dụng mẫu phù hợp một cách an toàn với luồng không giới hạn hoặc bạn chỉ cần sử dụng head
và tail
nếu bạn không muốn mọi thứ phát nổ?
Tôi đang sử dụng 'giải pháp val lười biếng: Danh sách [Move] = pathsToGoal trận { trường hợp (_, moveHistory) # :: _ => moveHistory.reverse trường hợp _ => List.empty [Move] }' và điều này không đánh giá đuôi. Có phải vì tôi đang sử dụng _? Ở đây trong trường hợp này, pathToGoal là một luồng vô tận – himanshu219