130 likes | 300 Vues
This document delves into the concept of iteration in LISP, highlighting the core iterative constructs such as 'do', 'dolist', and 'dotimes'. It explains their structure, including initialization, incrementing, and termination clauses, with examples that illustrate their use in functions such as factorial calculations. Additionally, it compares iteration with recursion, discussing their respective advantages and scenarios where one may be preferred over the other. The document also includes examples of loop constructs and demonstrates early termination in iterative processes.
E N D
Iteration “If I had a nickel for every time I've written ‘for (i = 0; i < N; i++)’ in C I'd be a millionaire.” - Mike Vanier
Do • The most basic iterative construct in LISP (do ([(var <init <incr>>)|var]*) (test result*) S-expression*) • “Initialize each var with its init, and execute the S-expressions until the test is true, modifying each var according to its incr. When test is true, return result” • Think of as do-until
Iteration Clause (do ([(var <init <incr>>)|var]*) (test result*) S-expression*) • Required, but can be empty • Introduces local variables, optionally gives them initial values, and optionally tells how to modify them with each iteration • Example: (x (y) (z 20) (a 1 (* a 2))) • x is set to nil by default, and is not modified every iteration • y is set to nil by default, and is not modified every iteration • z is set to 20, but is not modified every iteration • a is set to 1, and is multiplied by 2 every iteration
Test Clause (do ([(var <init <incr>>)|var]*) (test result*) S-expression*) • Required to be a non-empty list • Loop terminates when test evaluates to non-nil • Evaluates all of the result expressions and returns the value of the last
Do Example >(defun factorial (value) (do ((count 1 (1+ count)) (result 1)) ((> count value) result) (setf result (* count result)))) FACTORIAL >(factorial 3) 6
Order of Operations >(let ((x 'a)) (do ((x 1 (+ x 1)) (y x x) result) ((> x 5) result) (setf result (cons (list x y) result)))) ((5 4) (4 3) (3 2) (2 1) (1 A))
Iteration vs. Recursion • Iteration and recursion are capable of accomplishing the same things • Neither is more powerful than the other, but each has its advantages and disadvantages • In general, tail recursion is practically equivalent to iteration, and LISP actually optimizes tail recursive functions into iterative loops • With recursion, stack memory can be an issue • Choose the most natural and elegant solution to the problem
Do* • Bindings and incrementing in do occur in parallel • do* is the same as do, except the bindings in the iteration clause happen sequentially: >(do* ((a 0 (1+ a)) (b (+ 5 a) (* a b))) ((> a 5) b)) 3600
Dolist • Easy way to iterate over a list (dolist (element list result) S-expression*) • Iterate over each element of the list, execute the loop body, and at the end return the result >(let (result) (dolist (x '(a b c d) result) (setf result (cons x result)))) (D C B A)
Dotimes • Iterate over integers from 0 to n-1 (dotimes (int n result) S-expression*) • Example >(let (result) (dotimes (x 5 (reverse result)) (setf result (cons (list x (* x x)) result)))) ((0 0) (1 1) (2 4) (3 9) (4 16))
Terminating Early with Return • We can terminate early from iteration early using return, just like in typical imperative programming (somewhat like break as well) >(defun first-neg (list) (dolist (x list 'no-negatives) (if (minusp x) (return x)))) FIRST-NEG >(first-neg '(2 3 4 5 1 -3 -5 2 6 -2 3)) -3
Loop • loop is a complicated but powerful macro • The number of special directives available to loop is like a programming language in itself • We won’t go into too much detail on loop, but we’ll look at some examples • These examples use print, a simple output function that we’ll learn more about next class
>(loop for i in '(2 4 78) do (print i)) 2 4 78 NIL >(loop for i on '(2 4 78) do (print i)) (2 4 78) (4 78) (78) NIL >(loop for i from 1 to 3 do (print i)) 1 2 3 NIL >(loop with a = '(1 2 3) for i in a do (print i)) 1 2 3 NIL >(loop with result = '() for i from 5 downto 1 do (setf result (cons i result)) (when (= i 1) (return result))) (1 2 3 4 5) >(loop for i from 1 to 5 collect i) (1 2 3 4 5) Loop Examples