2010-12-19 22 views
5

में एक कुशल संग्रह समारोह मैं लिस्प सीख रहा हूं और परिणामों की एक सूची एकत्र करने के लिए निम्न कार्य लिखा है।सामान्य लिस्प

(defun collect (func args num) 
    (if (= 0 num) 
    () 
     (cons (apply func args) 
     (collect func args (- num 1))))) 

यह निर्मित लूप फ़ंक्शन में समान आउटपुट का उत्पादन करता है।

CL-USER> (collect #'random '(5) 10) 
(4 0 3 0 1 4 2 1 0 0) 
CL-USER> (loop repeat 10 collect (random 5)) 
(3 3 4 0 3 2 4 0 0 0) 

हालांकि मेरी कलेक्ट समारोह ढेर चल रही है जब मैं एक सूची 100,000 तत्वों लंबे

CL-USER> (length (collect #'random '(5) 100000)) 
Control stack guard page temporarily disabled: proceed with caution 

उत्पन्न करने के लिए जबकि लूप संस्करण नहीं

CL-USER> (length (loop repeat 100000 collect (random 5))) 
100000 

करता है तब क्या मैं अपने लिए कर सकते हैं की कोशिश संस्करण अधिक अंतरिक्ष कुशल, वहाँ consans के विकल्प हैं? मुझे लगता है कि यह पूंछ रिकर्सिव है। मैं एसबीसीएल का उपयोग कर रहा हूँ। कोई भी मदद बहुत अच्छी रहेगी।

उत्तर

10

पूंछ कॉल अनुकूलन करने के लिए एएनएसआई मानक द्वारा सामान्य लिस्प कार्यान्वयन की आवश्यकता नहीं है; हालांकि, उनके नमक (एसबीसीएल समेत) के लायक अधिकांश अनुकूलित करते हैं।

दूसरी ओर, आपका कार्य पूंछ रिकर्सिव नहीं है।

 
    (defun collect (func args num) 
     (labels ((frob (n acc) 
       (if (= 0 n) 
        acc 
        (frob (1- n) (cons (apply func args) acc))))) 
     (frob num nil))) 

(मूल मानकों समारोह और ARGS स्थानीय समारोह में समाप्त हो जाते हैं क्योंकि वे इसे करने के लिए recpect के साथ लगातार कर रहे हैं: यह मध्यवर्ती परिणाम जमा के लिए एक अतिरिक्त पैरामीटर शुरू करने की आम चाल का उपयोग करके एक में बदल सकता है)।

1

ठीक है, पुनरावृत्ति का विकल्प पुनरावृत्ति है।

आपको पता होना चाहिए कि आम लिस्प को इसके कार्यान्वयनकर्ताओं, से योजना के विपरीत पूंछ रिकर्सन की आवश्यकता नहीं है।

(defun mycollect (func args num) 
    (let ((accumulator '()))  ; it's a null list. 
    (loop for i from 1 to num 
     do 
     ;;destructively cons up the accumulator with the new result + the old accumulator 
     (setf accumulator     
     (cons (apply func args) accumulator))) 
    accumulator))    ; and return the accumulator 
11

नहीं, यह पूंछ रिकर्सिव नहीं है।

(defun collect (func args num) 
    (if (= 0 num) 
    () 
     (cons (apply func args) 
      (collect func args (- num 1))))) 

आप अपने कोड को देखें, तो आपकी कॉल इकट्ठा करने के लिए चारों ओर एक कान्स है: न तो एएनएसआई कॉमन लिस्प यह है और न ही अपने कोड के बारे में कुछ कहते हैं। इस CONS को संग्रह करने के लिए रिकर्सिव कॉल का मान प्राप्त होता है। तो संग्रह पूंछ रिकर्सिव नहीं हो सकता है। अपने फ़ंक्शन को उस चीज़ पर फिर से लिखना अपेक्षाकृत सरल है जो एक संचयक चर को पेश करके पूंछ को रिकर्सिव दिखता है। विभिन्न लिस्प या योजना साहित्य का वर्णन करना चाहिए। मत करो, DOTIMES, DOLIST, लूप, मानचित्र, MAPCAR, ...

कॉमन लिस्प मानक नहीं करता है:

कॉमन लिस्प में डिफ़ॉल्ट तरीका एक सतत गणना कार्यक्रम के कई पुनरावृत्ति निर्माणों में से एक का उपयोग करना है पूंछ कॉल अनुकूलन (टीसीओ) प्रदान करें। यह निर्दिष्ट करना होगा कि टीसीओ को कई अन्य भाषा सुविधाओं की उपस्थिति में क्या करना चाहिए। उदाहरण के लिए गतिशील बाध्यकारी और विशेष चर का टीसीओ पर असर पड़ता है। लेकिन आम लिस्प मानक सामान्य रूप से टीसीओ के बारे में कुछ भी नहीं और टीसीओ के संभावित प्रभावों के बारे में कुछ भी नहीं कहता है। टीसीओ एएनएसआई आम लिस्प मानक का हिस्सा नहीं है।

कई सामान्य लिस्प कार्यान्वयन के पास कंपाइलर स्विच के साथ विभिन्न पूंछ कॉल अनुकूलन को सक्षम करने का एक तरीका है। ध्यान दें कि उनको सक्षम करने के लिए दोनों तरीके और सीमाएं कार्यान्वयन विशिष्ट हैं।

सारांश: सामान्य लिस्प में पुनरावृत्ति संरचनाओं का उपयोग करें और पुनरावृत्ति नहीं।

(defun collect (func args num) 
    (loop repeat num 
     collect (apply #'func args))) 

जोड़ा गया बोनस: इसे पढ़ना आसान है।

संबंधित मुद्दे