The Loop Macro - PowerPoint PPT Presentation

About This Presentation
Title:

The Loop Macro

Description:

... of these examples will just print out the sequence ... (loop repeat 10 for a = 1 then ( a 1) do (print a) ... prints the list 120 through 126 and returns nil ... – PowerPoint PPT presentation

Number of Views:59
Avg rating:3.0/5.0
Slides: 19
Provided by: NKU
Learn more at: https://www.nku.edu
Category:
Tags: loop | macro | prints

less

Transcript and Presenter's Notes

Title: The Loop Macro


1
The Loop Macro
  • Many of the CL functions are actually macros
    (let, progn, if, etc)
  • The most complicated macro in CL is probably the
    Loop macro
  • The Loop macro gives you an alternative loop
    other than do, dotimes, dolist
  • This Loop can act like a counter-controlled loop,
    a conditional loop, or some combination
  • What makes the Loop unique is that it allows you
    to take the result of each iteration and combine
    them into a collection or into a single atom
  • We explore the Loop macro here, not in complete
    detail because there does not seem to be any
    single reference that completely understands the
    Loop
  • instead, we will mostly explore it through
    examples

2
What Loop Can Do
  • To start off with, we look at some specific
    examples just to see how the Loop macro can be
    varied to do different things

Using sum (loop for i in '(1 2 3) sum
i) 6 Combining (loop for x in '(1 2 3) for y in
'(4 5 5) collect (list x y)) ((1 4) (2 5)
(3 5)) Nesting (loop for i in '(1 2 3) collect
(list i (loop for j in '(4 5 6) collect
j))) ((1 (4 5 6)) (2 (4 5 6)) (3 (4 5 6)))
Simple counting loop (loop for i in '(1 2 3) do
(print i)) 1 2 3 NIL More complex
usage (loop for i in (1 2 3) collect (
i 2) do (print i)) 1 2 3 (2 4 6)
3
Components of the Loop
  • Loop prolog
  • Components evaluated prior to loop execution
    including variable initializations and any
    initially clause
  • Loop body
  • The forms that are executed during each
    iteration, they include executable statements in
    the block of code, termination tests, step
    increments, and collection statements
  • Loop termination
  • Statements in a finally clause are executed here
    and whatever was accumulated is returned
    (otherwise the loop returns nil)

4
Example Loop Components
(loop for i from 1 to (compute-top-value)
first clause while (not (unacceptable
i)) second clause collect (square i)
third clause do (format t "Working
on D now" i) fourth clause when
(evenp i) fifth clause do
(format t "D is a non-odd number" i)
finally (format t "About to exit!")) sixth
clause
  • This loop contains
  • An initialization clause
  • i from 1 to what (compute-top-value) returns
  • Two terminating clauses (one explicit)
  • either once i exceeds the top value, or if i is
    unacceptable
  • A collection clause
  • which will return the list of each (square i)
  • A body
  • the do statement which outputs one to two
    statements depending on if the when clause is t
    or nil
  • A finalize clause which exits once the loop is
    ready to terminate

5
Loop Initializations
  • Loops will always start with (loop
  • Followed by any initializations which are done
    using for and as
  • for is used to initialize variables sequentially
    and as is used to initialize variables in
    parallel
  • Loop stepping and termination are determined by
    supplying several possible terms
  • in list iterate for each item in the supplied
    list
  • from x to y iterate across the range supplied
  • alternatives are downfrom , upfrom, downto, upto,
    below, above
  • step-size defaults to 1/-1 but you can supply
    by to change the step size (such as from 3 to
    10 by 2)
  • from and by can be given in either order (for i
    by 3 from 1 to 100)
  • on list same as in list except that the whole
    list is used during each iteration and then the
    list is set to the cdr of the list
  • x y then z initializes x to y and then
    changes it to z afterward
  • this makes more sense when z is an expression
    like ( x 5)
  • across array binds the variable to each element
    of a given array
  • (for i across x do) note that this covers the
    entire array even nil items

6
Examples
Note all of these examples will just print out
the sequence (loop for a in '((1 2 3) (4 5 6) (7
8 9)) do (print a)) (1 2 3) (4 5 6) (7 8
9) (loop for a from 1 to 10 by 2 do (print a))
prints 1 3 5 7 9 (loop for a downfrom 10 to 1 do
(print a)) prints 10 9 8 1 (loop for a from 1
below 10 by 4 do (print a)) prints 1 5 9 (loop
for i upfrom 10 to 20 do (print i)) prints 10
11 12 20 (loop for i on '(1 2 3 4) do (print
i)) (1 2 3 4) (2 3 4) (3 4) (4) (loop for a
1 then ( a 10) for i from 1 to 5 do (print a))
prints 1 11 21 31 41 (loop for a across (1 2
3) do (print a)) prints 1 2 3
7
More on Initializations
  • Any variables initialized in the loop are bound
    inside the loop only and lose their scope
    afterward
  • The with statement allows you to declare and
    initialize additional local variables aside from
    any declared through the initialization processes
    we saw on the last slide
  • the with statements perform initializations
    sequentially (as in let)
  • use and in between the initializations to perform
    them in parallel
  • Note that it is difficult to use with/and when
    using the various other initializations covered
    on the last slide, so these are less useful
  • Example (loop with a 1 with b a collect b)
  • This is an infinite loop since we did not provide
    a terminating condition
  • Example (loop for i in (1 2 3) and a i
    collect a)
  • returns (nil 1 2)
  • while (loop for i in (1 2 3) with a i collect
    a)
  • returns (nil nil nil)

8
Accumulation Clauses
  • After initialization, your loop can contain
    executable statements as you would include in do,
    dotimes and dolist statements
  • But you can also specify accumulation clauses
  • collect collect the response of the next
    statement into a list, which is returned after
    the loop terminates
  • append same as collect except that the items
    collected are expected to already be in a list
  • nconc same as append but destructive
  • sum performs a running total on the value
    returned by the next statement, and returns this
    total when the loop terminates
  • count counts and returns the number of times
    the next statement is true
  • maximize, minimize returns the max/min value
    provided by the next statement across all loop
    iterations

9
Examples
(loop for i from 2 to 100 append (if (prime i)
(list i) nil)) note the use of append here,
if we used collect, we would get nils in our
return list (2 3 nil 5 nil 7 ) (loop for i from
2 to 100 count (prime i)) returns 25 ( of
primes in 2..100) (loop for name in '(fred sue
alice joe june) for kids in '((bob ken)
( ) ( ) (kris sunshine) ( )) collect name
append kids) (FRED BOB KEN SUE ALICE JOE KRIS
SUNSHINE JUNE) (loop for i in '(bird 3 4 turtle
(1 . 4) horse cat) when (symbolp i) collect i)
(BIRD TURTLE HORSE CAT) (loop for i across a
maximize i) Returns the maximum from array a
10
Finally
  • The finally clause is optional
  • If specified, it is executed one time after the
    final loop iteration
  • The finally clause can used to clean up what the
    loop was doing (for instance, closing a file)
  • Note that the finally clause is circumvented on
    certain circumstances that we will cover

(loop for i from 1 to 10 by 3 collect i finally
(print i)) 13 (1 4 7 10) (loop for i from 2 to
100 with x 0 append (if (prime i) (list i) nil)
do (if (prime i) (setf x ( x 1))) finally
(print x)) 25 (2 3 5 7 11 13 17 19 23 29 31 37
41 43 47 53 59 61 67 71 73 79 83 89 97) (loop
for i from 1 to 10 with x 2 sum (if ( (mod i
x) 0) (progn (setf x ( x 1)) i) 0) finally
(print x)) 11 54
11
Repeat Clause
  • Instead of using variable initialization over
    some range (such as with in, from, to, etc) you
    can use the repeat clause
  • This evaluates the next form and iterates that
    many times
  • (loop repeat 10 ) repeats 10 times
  • (loop repeat (foo x) ) repeats (foo x) times
  • The form is only evaluated once
  • The repeat clause does not provide you a loop
    index to reference but you can make your own
  • (loop repeat 10 for a 1 then ( a 1) do (print
    a))
  • Notice here that a is a local variable but not
    controlling the loop
  • If the form returns 0 or a negative number, the
    loop body is never executed but the finally
    clause is executed
  • Consider the following loop it will print
    repeating from 0 to 9 times and then print done

(loop repeat (random 10) do (print 'repeating)
finally (print 'done)
12
Prematurely Exiting A Loop
  • A for loop can be prematurely terminated by using
    one of
  • always, unless, thereis which can return a
    specified value
  • until a given condition becomes true
  • while a given condition is not false
  • The first group (always, never, thereis) will
    return a t/nil value from the loop upon
    termination
  • these return t if the condition is not violated
    or nil otherwise
  • always returns t if the condition provided is
    always t
  • never returns t if the condition provided is
    never t
  • thereis returns t if the condition provided is t
    once (the loop terminates as soon as one instance
    is found)
  • Note these cannot be used in conjunction with a
    collection mechanism without using an into clause
    see the example that follows
  • If there is a finally clause
  • it is executed after a normal loop terminates
    whether normally or by until or while
  • but it does not get executed if the loop is
    terminated by always, never or thereis

13
More Examples
(loop repeat 10 with x 1 until (gt x 10) do
(print x) (setf x ( x x))) -- prints 1 2 4 8
and returns NIL (loop for i from 120 to 130
never (prime i) do (print i)) -- prints the
list 120 through 126 and returns nil (loop for i
from 100 to 200 do (print i) thereis (prime i))
-- outputs 100 and 101 and then returns
t (loop for i from 1 to 10 until (gt ( i i) 60)
collect ( i i) into x finally (return x)) --
returns (1 4 9 16 25 36 49) notice into x which
allows us to collect a value while using a
terminating condition (loop for i across a never
(null i) sum i into x finally (return (/ x
(length a)))) Here, we are summing up all
elements of array a into variable x as long as
none are nil, the loop terminates if we find a
nil and returns nil, otherwise this returns the
average
14
Some More Loop Examples
(setf calories 0) (defun eat ( ) (declare
(special calories)) (setf calories (
calories ( 50 (random
250))))) (defun hungry-p ( ) (declare
(special calories)) (lt calories
600)) (loop while (hungry-p) do
(eat)) NIL calories 640
(loop for i from 1 to 3 do (print i)
(print ( i i))) this loop has two
executable statements so prints 6 things (1 1 2 4
3 9)
(let ((stack '(a b c d e f))) (loop for item
(length stack) then (pop stack)
collect item while stack)) (6 A B C D
E F)
15
Using When and Unless
  • Two additional clauses that can be supplied in
    the Loop macro are when and unless
  • Recall the functions (when condition body) and
    (unless condition body)
  • In this case, like with other Loop clauses,
    when/unless will not appear in ( )
  • We can also use this with a return clause to
    prematurely exit the loop (and optionally return
    a value)

(loop for i from 100 to 200 when (prime i) sum
i) (loop for i in (1 2 a 3 b 4 hi) when
(numberp i) collect i) (loop for i in '(1 2 a 3 b
4) when (numberp i) unless (evenp i) do (print
i))
(loop for i in '(1 2 a 4 5) unless (numberp i)
return i sum i)
16
Some Variations
  • Initialization and stepping can also be done to
    the values of a hash table or values in a package
  • We will omit those so that its not more confusing
    than necessary!
  • If we do not supply any Loop keywords, we have an
    infinite loop
  • (loop body) is an infinite loop on body
  • we can use return statements to exit the loop to
    prevent it being infinite
  • Loops can be nested
  • Loop iterators can be applied in parallel
  • (loop for x from 1 to 10 for y from 11 to 20 do
    (print (list x y)) prints the list ((1 11) (2
    12) (3 13)(10 20))
  • Loop clauses can be grouped
  • see the example on the next slide
  • The variable it is a specially reserved variable
  • (loop for i in '(1 2 3 4 5 6) when (and (gt i 3)
    i) collect it)
  • returns (4 5 6)
  • (loop for i in '(1 2 3 4 5 6) when (and (gt i 3)
    i) return it)
  • returns 4

17
Grouping Clauses Example
(loop for i in '(1 324 2345 323 2 4 235 252)
when (oddp i) do (print i) and collect i
into odd-numbers and do (terpri)
else i is even.
collect i into even-numbers finally (return
(values odd-numbers even-numbers))) gt 1 gt gt
2345 gt gt 323 gt gt 235 and returns (1 2345 323
235), (324 2 4 252)
18
Follow These Rules
  • The Loop mechanism can be treacherous to use and
    difficult to understand how and when to use it
  • However, if you want to try, your loop must be in
    the proper order
  • Start with your initially clause (if any)
  • Follow it by your for, with and repeat clause(s)
  • Next you can supply your conditional clauses
    (when/unless) and unconditional clauses (do) and
    any accumulation statements or termination
    test(s)
  • End with your finally clause
  • When the loop is iterating, the body is executed
    by
  • first stepping through any iteration control
    variables
  • then doing in the order that they appear in the
    loop body
  • any conditional or unconditional execution
    statements, any accumulation clauses, any
    termination test clauses
  • if any of the clauses in the loop body terminate
    the loop, the rest of the body is skipped and the
    loop returns
  • the finally clause is executed unless the loop is
    terminated by a return, always, never or thereis
    clause
Write a Comment
User Comments (0)
About PowerShow.com