Zoeken…


Begrensde lussen

We kunnen een actie een aantal keren repeat met 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)

Lussen over reeksen

(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

Hier is een samenvatting van de zoekwoorden

keyword Volgorde type Variabel type
in lijst element van lijst
Aan lijst sommige cdr van lijst
aan de overkant vector element van vector

Lussen over hashtabellen

(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))

Eenvoudig LOOP-formulier

Eenvoudig LOOP-formulier zonder speciale zoekwoorden:

(loop forms...)

Om uit de lus te breken kunnen we (return <return value>) `

Een paar voorbeelden:

(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!~%")))))

Lussen over pakketten

(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))

Rekenkundige Lussen

(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

Destructurering in FOR-verklaringen

We kunnen lijsten met samengestelde objecten vernietigen

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)

We kunnen ook een lijst zelf vernietigen

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)

Dit is handig als we alleen bepaalde elementen willen doorlopen

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 gebruiken om een term te negeren:

(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 als een uitdrukking

In tegenstelling tot de loops in bijna elke andere programmeertaal die tegenwoordig wordt gebruikt, kan de LOOP in Common Lisp worden gebruikt als een uitdrukking:

(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 zorgt ervoor dat de LOOP de grootste waarde retourneert die is geëvalueerd. MINIMIZE is het tegenovergestelde van MAXIMIZE .

(loop repeat 100
      for x = (random 1000)
      maximize x)

COUNT geeft aan hoe vaak een expressie tijdens de lus als niet- NIL geëvalueerd:

(loop repeat 100
      for x = (random 1000)
      count (evenp x))

LOOP ook equivalenten van some , every en notany functies:

(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))

... behalve dat ze niet beperkt zijn tot het herhalen van reeksen:

(loop for value = (read *standard-input* nil :eof)
   until (eq value :eof)
   never (stringp value))

LOOP waarde-genererende werkwoorden kunnen ook worden geschreven met een -ing achtervoegsel:

(loop repeat 100
      for x = (random 1000)
      minimizing x)

Het is ook mogelijk om de door deze werkwoorden gegenereerde waarde vast te leggen in variabelen (die impliciet door de LOOP macro worden gecreëerd), zodat je meer dan één waarde tegelijk kunt genereren:

 (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)))

U kunt meer dan één clausule voor collect , count , etc. hebben die in dezelfde uitvoerwaarde wordt verzameld. Ze worden in volgorde uitgevoerd.

Het volgende converteert een associatielijst (die u kunt gebruiken met assoc ) naar een eigenschappenlijst (die u kunt gebruiken met getf ):

(loop for (key . value) in assoc-list
      collect key
      collect value)

Hoewel dit een betere stijl is:

(loop for (key . value) in assoc-list
      append (list key value))

Voorwaardelijk uitvoeren van LOOP-clausules

LOOP heeft zijn eigen IF instructie die kan bepalen hoe de clausules worden uitgevoerd:

(loop repeat 1000
      for x = (random 100)
      if (evenp x)
        collect x into evens
      else
        collect x into odds
      finally (return (values evens odds)))

Het combineren van meerdere clausules in een IF-body vereist speciale syntaxis:

 (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)))

Parallelle herhaling

Meerdere FOR clausules zijn toegestaan in een LOOP . De lus eindigt wanneer de eerste van deze clausules eindigt:

(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))

Andere clausules die bepalen of de lus moet doorgaan, kunnen worden gecombineerd:

(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)

Bepaal welke lijst langer is en stop iteratie zodra het antwoord bekend is:

(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)))

De elementen van een lijst nummeren:

(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))

Zorg ervoor dat alle nummers in een lijst even zijn, maar alleen voor de eerste 100 items:

(assert
   (loop for number in list
         repeat 100
         always (evenp number)))

Geneste Iteratie

Met de speciale LOOP NAMED foo syntaxis kun je een lus maken die je eerder kunt verlaten. De exit wordt uitgevoerd met behulp van return-from en kan worden gebruikt vanuit geneste lussen.

Het volgende gebruikt een geneste lus om te zoeken naar een complex nummer in een 2D-array:

(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))))

RETURN-clausule versus RETURN-formulier.

Binnen een LOOP kunt u het Common Lisp-formulier (return) in elke expressie, waardoor het LOOP formulier onmiddellijk de waarde beoordeelt die moet worden return .

LOOP heeft ook een return clausule die bijna identiek werkt, het enige verschil is dat je het niet omringen met haakjes. De clausule wordt gebruikt in de DSL van LOOP , terwijl de vorm wordt gebruikt in uitdrukkingen.

(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))

Het ding na moet finally een uitdrukking zijn, dus moet de (return) vorm worden gebruikt en niet de 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.

Lussen over een venster van een lijst

Enkele voorbeelden voor een venster van maat 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


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow