2011-05-29 6 views
6

मैं आम लिस्प के लिए नया हूं। हास्केल में, आप इस तरह कुछ कर सकते हैं:क्या लिस्प के पास हास्केल के कुछ काम करते हैं जबकि समारोह?

Prelude> takeWhile (<= 10) [k | k <- [1..]] 
[1,2,3,4,5,6,7,8,9,10] 

क्या यह लिस्प में संभव है? एक अनंत सूची के साथ जरूरी नहीं है, लेकिन किसी भी सूची के साथ।

उत्तर

11

आप इस्तेमाल कर सकते हैं LOOP:

(setq *l1* (loop for x from 1 to 100 collect x)) 
(loop for x in *l1* while (<= x 10) collect x) 

तुम सच में एक अलग समारोह के रूप में यह की जरूरत है:

(defun take-while (pred list) 
    (loop for x in list 
     while (funcall pred x) 
     collect x)) 

और यहाँ हम कर रहे हैं:

T1> (take-while (lambda (x) (<= x 10)) *l1*) 
(1 2 3 4 5 6 7 8 9 10) 

लेकिन हम की तुलना:

(loop for x in *l1* while (<= x 10) collect x) 
(take-while (lambda (x) (<= x 10)) *l1*) 

मुझे लगता है कि मैं सिर्फ लूप के साथ रहूंगा।

अनंत दृश्यों के लिए, आप Series पर एक नज़र ले सकता है:

T1> (setq *print-length* 20) 
20 
T1> (setq *l1* (scan-range :from 1)) 
#Z(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...) 
T1> (until-if (lambda (x) (> x 10)) *l1*) 
#Z(1 2 3 4 5 6 7 8 9 10) 
4

यह क्या करना चाहिए ...

(defun take-while (list test) 
    (and list (funcall test (car list)) 
     (cons (car list) (take-while (cdr list) test)))) 

(take-while '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) (lambda (x) (< x 10))) 
--> (1 2 3 4 5 6 7 8 9) 

हालांकि इस "प्राकृतिक" कार्यान्वयन पूंछ पुनरावर्ती नहीं है और दुर्घटना सकता है बड़ी सूचियों के लिए।

एक स्पष्ट धक्का-nreverse दृष्टिकोण (एक आम पैटर्न) हो सकता है

(defun take-while (list test) 
    (do ((res nil)) 
     ((or (null list) (not (funcall test (car list)))) 
     (nreverse res)) 
    (push (car list) res) 
    (setf list (cdr list)))) 

एक पुनरावर्ती (लेकिन पूंछ पुनरावर्ती, इसलिए शायद सबसे सीएल कार्यान्वयन के साथ ठीक) IMO निम्नलिखित हो सकता है:

(defun take-while (list test) 
    (labels ((rec (res x) 
      (if (and x (funcall test (car x))) 
       (rec (cons (car x) res) (cdr x)) 
       (nreverse res)))) 
    (rec nil list))) 

ध्यान दें कि हालांकि यह गारंटी नहीं है कि एक सामान्य लिस्प कार्यान्वयन पूंछ-कॉल अनुकूलन को संभालेगा।

+1

नहीं एक अच्छा विचार है। यह पूंछ भी नहीं है। यह किसी भी सूची में ढेर को उड़ा देगा ... –

+1

स्वीकार करने के लिए धन्यवाद, लेकिन ध्यान दें कि शायद डैनली उत्तर बेहतर है ... यह पूंछ-रिकर्सिव – 6502

+1

@rainer joswig भी नहीं है: मैं मानता हूं कि लूप बेहतर है – 6502

3

कुछ भाषाएं तृतीय पक्ष पुस्तकालयों के रूप में एक हास्केल-शैली सूची API प्रदान करती हैं, जिसमें अनंत धाराओं के समर्थन के साथ या बिना।

कुछ उदाहरण:

याद रखें कि takeWhile अपेक्षाकृत एक दृश्य के ऊपर लागू करने के लिए आसान है, और के रूप में हास्केल में दी गई है है:

takeWhile _ []   = [] 
takeWhile p (x:xs) 
      | p x  = x : takeWhile p xs 
      | otherwise = [] 
+0

हालांकि यह मेरे प्रत्यक्ष प्रश्न को कम नहीं करता है, यह जवाब बहुत अंतर्दृष्टिपूर्ण है। धन्यवाद! – Mike

3

CL-LAZY library सामान्य लिस्प के लिए आलसी कॉलिंग लागू करता है और आलसी जागरूकता वाला एक ले-टाइम फ़ंक्शन प्रदान करता है। आप इसे Quicklisp के साथ इंस्टॉल कर सकते हैं और इसे आज़माएं।

+0

अरे, यह अच्छा है! धन्यवाद! – Mike

0

आप (Paul Graham's On Lisp से) बंद का उपयोग कर आम तुतलाना में एक आलसी मूल्यांकन हो सकता है: तो फिर

(defun lazy-right-fold (comb &optional base) 
    "Lazy right fold on lists." 
    (labels ((rec (lst) 
      (if (null lst) 
       base 
       (funcall comb 
          (car lst) 
          #'(lambda() (rec (cdr lst))))))) 
    #'rec)) 

, ले, जबकि हो जाता है:

(defun take-while (pred lst) 
    (lazy-right-fold #'(lambda (x f) (
         (if (test x) 
          (cons x (funcall f)) 
          (funcall f))) 
        nil)) 
संबंधित मुद्दे