common-lisp
LOOP, पुनरावृत्ति के लिए एक आम लिस्प मैक्रो
खोज…
बंधे हुए लूप
हम दोहराव का उपयोग करके किसी संख्या को कई बार repeat
।
CL-USER> (loop repeat 10 do (format t "Hello!~%")) Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! NIL CL-USER> (loop repeat 10 collect (random 50)) (28 46 44 31 5 33 43 35 37 4)
दृश्यों पर लूपिंग
(loop for i in '(one two three four five six)
do (print i))
(loop for i in '(one two three four five six) by #'cddr
do (print i)) ;prints ONE THREE FIVE
(loop for i on '(a b c d e f g)
do (print (length i))) ;prints 7 6 5 4 3 2 1
(loop for i on '(a b c d e f g) by #'cddr
do (print (length i))) ;prints 7 5 3 1
(loop for i on '(a b c)
do (print i)) ;prints (a b c) (b c) (c)
(loop for i across #(1 2 3 4 5 6)
do (print i)) ; prints 1 2 3 4 5 6
(loop for i across "foo"
do (print i)) ; prints #\f #\o #\o
(loop for element across "foo"
for i from 0
do (format t "~a ~a~%" i element)) ; prints 0 f\n1 o\n1 o
यहां कीवर्ड का सारांश दिया गया है
कीवर्ड | अनुक्रम प्रकार | चर प्रकार |
---|---|---|
में | सूची | सूची का तत्व |
पर | सूची | सूची के कुछ सीडीआर |
भर में | वेक्टर | वेक्टर का तत्व |
हैश टेबल्स पर लूपिंग
(defvar *ht* (make-hash-table))
(loop for (sym num) on
'(one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8 nine 9 ten 10)
by #'cddr
do (setf (gethash sym *ht*) num))
(loop for k being each hash-key of *ht*
do (print k)) ; iterate over the keys
(loop for k being the hash-keys in *ht* using (hash-value v)
do (format t "~a=>~a~%" k v))
(loop for v being the hash-value in *ht*
do (print v))
(loop for v being each hash-values of *ht* using (hash-key k)
do (format t "~a=>~a~%" k v))
सरल LOOP फार्म
विशेष कीवर्ड के बिना सरल LOOP फॉर्म:
(loop forms...)
लूप से बाहर निकलने के लिए हम उपयोग कर सकते हैं (return <return value>)
`
कुछ उदाहरण:
(loop (format t "Hello~%")) ; prints "Hello" forever
(loop (print (eval (read)))) ; your very own REPL
(loop (let ((r (read)))
(typecase r
(number (return (print (* r r))))
(otherwise (format t "Not a number!~%")))))
पैकेजों पर लूपिंग
(loop for s being the symbols in 'cl
do (print s))
(loop for s being the present-symbols in :cl
do (print s))
(loop for s being the external-symbols in (find-package "COMMON LISP")
do (print s))
(loop for s being each external-symbols of "COMMON LISP"
do (print s))
(loop for s being each external-symbol in pack ;pack is a variable containing a package
do (print s))
अंकगणित लूप्स
(loop for i from 0 to 10
do (print i)) ; prints 0 1 2 3 4 5 6 7 8 9 10
(loop for i from 0 below 10
do (print i)) ; prints 0 1 2 3 4 5 6 7 8 9 10
(loop for i from 10 above 0
do (print i)) ; prints 10 9 8 7 6 5 4 3 2 1
(loop for i from 10 to 0
do (print i)) ; prints nothing
(loop for i from 10 downto 0
do (print i)) ; prints 10 9 8 7 6 5 4 3 2 1 0
(loop for i downfrom 10 to 0
do (print i)) ; same as above
(loop for i from 1 to 100 by 10
do (print i)) ; prints 1 11 21 31 41 51 61 71 81 91
(loop for i from 100 downto 0 by 10
do (print i)) ; prints 100 90 80 70 60 50 40 30 20 10 0
(loop for i from 1 to 10 by (1+ (random 3))
do (print i)) ; note that (random 3) is evaluated only once
(let ((step (random 3)))
(loop for i from 1 to 10 by (+ step 1)
do (print i))) ; equivalent to the above
(loop for i from 1 to 10
for j from 11 by 11
do (format t "~2d ~3d~%" i j)) ;prints 1 11\n2 22\n...10 110
बयानों के लिए विनाशकारी
हम यौगिक वस्तुओं की सूचियों को नष्ट कर सकते हैं
CL-USER> (loop for (a . b) in '((1 . 2) (3 . 4) (5 . 6)) collect a)
(1 3 5)
CL-USER> (loop for (a . b) in '((1 . 2) (3 . 4) (5 . 6)) collect b)
(2 4 6)
CL-USER> (loop for (a b c) in '((1 2 3) (4 5 6) (7 8 9) (10 11 12)) collect b)
(2 5 8 11)
हम एक सूची को भी नष्ट कर सकते हैं
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) collect a)
(1 2 3 4 5 6)
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) collect b)
((2 3 4 5 6) (3 4 5 6) (4 5 6) (5 6) (6) NIL)
यह उपयोगी है जब हम केवल कुछ तत्वों के माध्यम से पुनरावृति करना चाहते हैं
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) by #'cddr collect a)
(1 3 5)
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) by #'cdddr collect a)
(1 4)
किसी शब्द को अनदेखा करने के लिए NIL
का उपयोग करना:
(loop for (a nil . b) in '((1 2 . 3) (4 5 . 6) (7 8 . 9))
collect (list a b)) ;=> ((1 3) (4 6) (7 9))
(loop for (a b) in '((1 2) (3 4) (5 6)) ;(a b) == (a b . nil)
collect (+ a b)) ;=> (3 7 11)
; iterating over a window in a list
(loop for (pre x post) on '(1 2 3 4 5 3 2 1 2 3 4)
for nth from 1
while (and x post) ; checks that we have three elements of the list
if (and (<= post x) (<= pre x)) collect (list :max x nth)
if (and (>= post x) (>= pre x)) collect (list :min x nth))
; The above collects local minima/maxima
अभिव्यक्ति के रूप में LOOP
आज उपयोग की जाने वाली लगभग हर अन्य प्रोग्रामिंग भाषा में छोरों के विपरीत, कॉमन लिस्प में LOOP
को एक अभिव्यक्ति के रूप में इस्तेमाल किया जा सकता है:
(let ((doubled (loop for x from 1 to 10
collect (* 2 x))))
doubled) ;; ==> (2 4 6 8 10 12 14 16 18 20)
(loop for x from 1 to 10 sum x)
MAXIMIZE
कारण बनता है कि LOOP
का मूल्यांकन किया गया सबसे बड़ा मान लौटाया जाए। MINIMIZE
के विपरीत है MAXIMIZE
।
(loop repeat 100
for x = (random 1000)
maximize x)
COUNT
आपको बताता है कि लूप के दौरान गैर- NIL
को कितनी बार अभिव्यक्ति का मूल्यांकन किया गया है:
(loop repeat 100
for x = (random 1000)
count (evenp x))
LOOP
में some
, every
और notany
फ़ंक्शन के notany
हैं:
(loop for ch across "foobar"
thereis (eq ch #\a))
(loop for x in '(a b c d e f 1)
always (symbolp x))
(loop for x in '(1 3 5 7)
never (evenp x))
... सिवाय इसके कि वे सीक्वेंस पर चलने तक सीमित नहीं हैं:
(loop for value = (read *standard-input* nil :eof)
until (eq value :eof)
never (stringp value))
LOOP
मूल्य-सृजन करने वाली क्रियाओं को भी एक प्रत्यय के साथ लिखा जा सकता है:
(loop repeat 100
for x = (random 1000)
minimizing x)
इन क्रियाओं द्वारा उत्पन्न मूल्य को चर में उत्पन्न करना भी संभव है (जो कि LOOP
मैक्रो द्वारा निहित रूप से बनाए गए हैं), इसलिए आप एक समय में एक से अधिक मूल्य उत्पन्न कर सकते हैं:
(loop repeat 100
for x = (random 1000)
maximizing x into biggest
minimizing x into smallest
summing x into total
collecting x into xs
finally (return (values biggest smallest total xs)))
आपके पास एक से अधिक collect
, count
, आदि खंड हो सकते हैं जो समान आउटपुट मान में एकत्रित होते हैं। उन्हें क्रम से निष्पादित किया जाएगा।
निम्नलिखित एक संपत्ति सूची में एक एसोसिएशन सूची (जिसका उपयोग आप assoc
साथ कर सकते हैं) में कनवर्ट करता है (जिसे आप getf
साथ उपयोग कर सकते हैं):
(loop for (key . value) in assoc-list
collect key
collect value)
हालांकि यह बेहतर शैली है:
(loop for (key . value) in assoc-list
append (list key value))
सशर्त रूप से LOOP क्लॉज़ निष्पादित किया जा रहा है
LOOP
का अपना IF
कथन है जो यह नियंत्रित कर सकता है कि खण्डों को कैसे निष्पादित किया जाता है:
(loop repeat 1000
for x = (random 100)
if (evenp x)
collect x into evens
else
collect x into odds
finally (return (values evens odds)))
एक IF बॉडी में कई क्लॉज़ को मिलाने के लिए विशेष सिंटैक्स की आवश्यकता होती है:
(loop repeat 1000
for x = (random 100)
if (evenp x)
collect x into evens
and do (format t "~a is even!~%" x)
else
collect x into odds
and count t into n-odds
finally (return (values evens odds n-odds)))
समानांतर Iteration
एकाधिक FOR
खंड एक में अनुमति दी जाती LOOP
। जब इन खंडों में से पहला खत्म हो जाता है तो लूप समाप्त हो जाता है:
(loop for a in '(1 2 3 4 5)
for b in '(a b c)
collect (list a b))
;; Evaluates to: ((1 a) (2 b) (3 c))
अन्य खंड जो निर्धारित करते हैं कि क्या लूप जारी रहना चाहिए संयुक्त हो सकता है:
(loop for a in '(1 2 3 4 5 6 7)
while (< a 4)
collect a)
;; Evaluates to: (1 2 3)
(loop for a in '(1 2 3 4 5 6 7)
while (< a 4)
repeat 1
collect a)
;; Evaluates to: (1)
निर्धारित करें कि कौन सी सूची लंबी है, उत्तर ज्ञात होते ही पुनरावृति काट देना:
(defun longerp (list-1 list-2)
(loop for cdr1 on list-1
for cdr2 on list-2
if (null cdr1) return nil
else if (null cdr2) return t
finally (return nil)))
किसी सूची के तत्वों की संख्या:
(loop for item in '(a b c d e f g)
for x from 1
collect (cons x item))
;; Returns ((1 . a) (2 . b) (3 . c) (4 . d) (5 . e) (6 . f) (7 . g))
सुनिश्चित करें कि किसी सूची में सभी संख्याएँ समान हैं, लेकिन केवल पहले 100 आइटमों के लिए:
(assert
(loop for number in list
repeat 100
always (evenp number)))
नेस्ट इटरेशन
विशेष LOOP NAMED foo
सिंटैक्स आपको एक लूप बनाने की अनुमति देता है जिससे आप जल्दी से बाहर निकल सकते हैं। निकास return-from
का उपयोग करके किया जाता return-from
, और नेस्टेड छोरों के भीतर से उपयोग किया जा सकता है।
निम्नलिखित एक नेस्टेड लूप का उपयोग करता है जो किसी जटिल संख्या को 2D सरणी में देखने के लिए करता है:
(loop named top
for x from 0 below (array-dimension *array* 1)
do (loop for y from 0 below (array-dimension *array* 0))
for n = (aref *array* y x)
when (complexp n)
do (return-from top (values n x y))))
रिटन क्लॉज बनाम रिटन फॉर्म।
एक LOOP
भीतर, आप किसी भी अभिव्यक्ति में कॉमन लिस्प (return)
फॉर्म का उपयोग कर सकते हैं, जिसके कारण LOOP
फॉर्म तुरंत return
दिए गए मूल्य का मूल्यांकन करेगा।
LOOP
में एक return
क्लॉज भी है जो लगभग समान रूप से काम करता है, एकमात्र अंतर यह है कि आप इसे कोष्ठक के साथ नहीं घेरते हैं। खण्ड का उपयोग LOOP
के डीएसएल के भीतर किया जाता है, जबकि प्रपत्र का उपयोग अभिव्यक्तियों के भीतर किया जाता है।
(loop for x in list
do (if (listp x) ;; Non-barewords after DO are expressions
(return :x-has-a-list)))
;; Here, both the IF and the RETURN are clauses
(loop for x in list
if (listp x) return :x-has-a-list)
;; Evaluate the RETURN expression and assign it to X...
;; except RETURN jumps out of the loop before the assignment
;; happens.
(loop for x = (return :nothing-else-happens)
do (print :this-doesnt-print))
finally
बात एक अभिव्यक्ति होनी चाहिए, इसलिए (return)
फॉर्म का इस्तेमाल किया जाना चाहिए न कि return
क्लॉज:
(loop for n from 1 to 100
when (evenp n) collect n into evens
else collect n into odds
finally return (values evens odds)) ;; ERROR!
(loop for n from 1 to 100
when (evenp n) collect n into evens
else collect n into odds
finally (return (values evens odds))) ;; Correct usage.
किसी सूची की विंडो पर लूपिंग
आकार 3 की विंडो के लिए कुछ उदाहरण:
;; Naïve attempt:
(loop for (first second third) on '(1 2 3 4 5)
do (print (* first second third)))
;; prints 6 24 60 then Errors on (* 4 5 NIL)
;; We will try again and put our attempt into a function
(defun loop-3-window1 (function list)
(loop for (first second third) on list
while (and second third)
do (funcall function first second third)))
(loop-3-window1 (lambda (a b c) (print (* a b c))) '(1 2 3 4 5))
;; prints 6 24 60 and returns NIL
(loop-3-window1 (lambda (a b c) (print (list a b c))) '(a b c d nil nil e f))
;; prints (a b c) (b c d) then returns NIL
;; A second attempt
(defun loop-3-window2 (function list)
(loop for x on list
while (nthcdr 2 x) ;checks if there are at least 3 elements
for (first second third) = x
do (funcall function first second third)))
(loop-3-window2 (lambda (a b c) (print (list a b c))) '(a b c d nil nil e f))
;; prints (a b c) (b c d) (c d nil) (c nil nil) (nil nil e) (nil e f)
;; A (possibly) more efficient function:
(defun loop-3-window2 (function list)
(let ((f0 (pop list))
(s0 (pop list)))
(loop for first = f0 then second
and second = s0 then third
and third in list
do (funcall function first second third))))
;; A more general function:
(defun loop-n-window (n function list)
(loop for x on list
while (nthcdr (1- n) x)
do (apply function (subseq x 0 n))))
;; With potentially efficient implementation:
(define-compiler-macro loop-n-window (n function list &whole w)
(if (typep n '(integer 1 #.call-arguments-limit))
(let ((vars (loop repeat n collect (gensym)))
(vars0 (loop repeat (1- n) collect (gensym)))
(lst (gensym)))
`(let ((,lst ,list))
(let ,(loop for v in vars0 collect `(,v (pop ,lst)))
(loop for
,@(loop for v0 in vars0 for (v vn) on vars
collect v collect '= collect v0 collect 'then collect vn
collect 'and)
,(car (last vars)) in ,lst
do ,(if (and (consp function) (eq 'function (car function))
w