Stream
(ओं) पर चल रहे फ़ंक्शन को लिखते समय, रिकर्सन के विभिन्न विचार हैं। पहले सामान्य अर्थ है, तो तुरन्त मूल्यांकन नहीं तो समारोह तुरंत वापस लौट, संकलक स्तर पर पुनरावर्ती नहीं है पूंछ के बाद से, लेकिन उसके परिणाम धारा पुनरावर्ती है:स्कैला में Stream.cons का उपयोग कर गैर-लीकिंग पूंछ-रिकर्सिव फ़ंक्शन कैसे लिखें?
final def simpleRec[A](as: Stream[A]): Stream[B] =
if (a.isEmpty) Stream.empty
else someB(a.head) #:: simpleRec(a.tail)
प्रत्यावर्तन के ऊपर धारणा किसी भी समस्याओं का कारण नहीं है । दूसरा एक संकलक स्तर पर सही मायने में पूंछ पुनरावर्ती है:
@tailrec
final def rec[A](as: Stream[A]): Stream[B] =
if (a.isEmpty) Stream.empty // A) degenerated
else if (someCond) rec(a.tail) // B) tail recursion
else someB(a.head) #:: rec(a.tail) // C) degenerated
समस्या है कि यहाँ C)
मामले, एक गैर tailrec कॉल के रूप में संकलक द्वारा पता लगाया जाता है, भले ही कोई वास्तविक कॉल किया जाता है। यह एक सहायक समारोह में धारा पूंछ बाहर बाँटे से बचा जा सकता:
@tailrec
final def rec[A](as: Stream[A]): Stream[B] =
if (a.isEmpty) Stream.empty
else if (someCond) rec(a.tail) // B)
else someB(a.head) #:: recHelp(a.tail)
@tailrec
final def recHelp[A](as: Stream[A]): Stream[B] =
rec(as)
हालांकि यह संकलित, इस दृष्टिकोण अंततः एक स्मृति रिसाव का परिणाम है। चूंकि पूंछ-रिकर्सिव rec
को अंततः recHelp
फ़ंक्शन से बुलाया जाता है, recHelp
फ़ंक्शन के ढेर फ्रेम में स्टीम हेड का संदर्भ होता है, और rec
कॉल रिटर्न तक स्ट्रीम को कचरा नहीं होने देता है, जो काफी लंबा हो सकता है (रिकर्सन चरणों के संदर्भ में) B)
पर कॉल की संख्या के आधार पर।
ध्यान दें कि असहिष्णु मामले में भी, यदि कंपाइलर @tailrec की अनुमति देता है, तो स्मृति लीक अभी भी मौजूद हो सकती है क्योंकि आलसी धारा पूंछ प्रभावी रूप से स्ट्रीम हेड के संदर्भ में अज्ञात ऑब्जेक्ट होल्डिंग बना देगा।
संबंधित http://stackoverflow.com/questions/12486762/scala-tail-recursive-stream-processor-function-defined-in-trait-holds-reference – ron
कोड के कामकाजी टुकड़े का कोई मौका भी देखें? अर्थात। एक ओओएम? – Chris
क्रिस: सुनिश्चित करें, दोनों की तुलना करें: https://gist.github.com/3769565 (2.10.0-M7 ok.scala के लिए ओम नहीं है) – ron