# HG changeset patch # User Steve Losh # Date 1507405558 14400 # Node ID 38345ccf034aaffbf80fba71f5e1f37da392f270 # Parent 9cbd4c08480e7be9f4f5382b02b11b2cf534f9d0 Iterate harder. diff -r 9cbd4c08480e -r 38345ccf034a src/problems.lisp --- a/src/problems.lisp Sat Oct 07 13:52:05 2017 -0400 +++ b/src/problems.lisp Sat Oct 07 15:45:58 2017 -0400 @@ -1893,9 +1893,9 @@ previous-digits current-digits))) (run-clock (seed) (iterate - (for current :in-lists (list (mapcar (rcurry #'digits :from-end t) - (digital-roots seed)) - '(nil))) ; final turn-off + (for current :in-list (mapcar (rcurry #'digits :from-end t) + (digital-roots seed)) + :finally nil) (for prev :previous current :initially nil) (summing (transition #'transition-sam prev current) :into sam) (summing (transition #'transition-max prev current) :into max) @@ -2222,8 +2222,6 @@ (test p61 (is (= 28684 (problem-61)))) (test p62 (is (= 127035954683 (problem-62)))) (test p63 (is (= 49 (problem-63)))) - - (test p74 (is (= 402 (problem-74)))) (test p79 (is (= 73162890 (problem-79)))) (test p92 (is (= 8581146 (problem-92)))) diff -r 9cbd4c08480e -r 38345ccf034a src/utils.lisp --- a/src/utils.lisp Sat Oct 07 13:52:05 2017 -0400 +++ b/src/utils.lisp Sat Oct 07 15:45:58 2017 -0400 @@ -1,15 +1,45 @@ (in-package :euler) -(defmacro-driver (FOR var ITERATING function SEED value) +(defmacro-driver (FOR var ITERATING function SEED value &optional + INCLUDE-SEED include-seed?) + "Iterate `var` over the series `(f seed), (f (f seed)), (f (f (f seed))), ...`. + + If `include-seed` is given the series will start with the seed itself first. + + Examples: + + (iterate (for n :iterating #'digital-sum :seed 10123456789) + (collect n) + (until (< n 10))) + ; => (46 10 1) + + (iterate (for n :iterating #'digital-sum :seed 10123456789 :include-seed t) + (collect n) + (until (< n 10))) + ; => (10123456789 46 10 1) + + " (let ((kwd (if generate 'generate 'for))) (with-gensyms (f) `(progn (with ,f = ,function) (,kwd ,var - :initially (funcall ,f ,value) + :initially ,(if include-seed? + value + `(funcall ,f ,value)) :then (funcall ,f ,var)))))) (defmacro-driver (FOR var IN-LOOPING list) + "Iterate `var` over `list`, looping when the end is reached. + + Example: + + (iterate (for x :in-looping '(1 2 3)) + (repeat 5) + (collect x)) + ; => (1 2 3 1 2) + + " (let ((kwd (if generate 'generate 'for))) (with-gensyms (l remaining) `(progn @@ -22,6 +52,14 @@ ,remaining))))))) (defmacro-driver (FOR var KEY function &sequence) + "Iterate `var` numerically as with `FOR`, applying `function` to the numbers. + + Example: + + (iterate (for x :key #'evenp :from 0 :to 8) (collect x)) + ; => (T NIL T NIL T NIL T NIL T) + + " (let ((kwd (if generate 'generate 'for))) (with-gensyms (i f) `(progn @@ -29,6 +67,57 @@ (generate ,i ,@(losh::expand-iterate-sequence-keywords)) (,kwd ,var :next (funcall ,f (next ,i))))))) +(defmacro-driver (FOR var IN-LIST list &optional + BY (step-function '#'cdr) + INITIALLY (initial-value nil initial-value?) + FINALLY (final-value nil final-value?)) + "Iterate `var` over `list` like vanilla `FOR var IN`, but with more options. + + If `initially` is given, `var` will be bound to it on the first iteration, + before proceeding to iterate over the list. + + If `finally` is given, `var` will be bound to it on one more iteration after + the end of the list has been reached. + + Examples: + + (iterate (for x :in-list '(1 2 3)) + (collect x)) + ; => (1 2 3) + + (iterate (for x :in-list '(1 2 3) :initially 0) + (collect x)) + ; => (0 1 2 3) + + (iterate (for x :in-list '(1 2 3) :finally 4) + (collect x)) + ; => (1 2 3 4) + + (iterate (for x :in-list '(1 2 3) :initially 0 :finally 4) + (collect x)) + ; => (0 1 2 3 4) + + " + (let ((kwd (if generate 'generate 'for))) + (with-gensyms (l i f done) + `(progn + (with ,l = ,list) + ,@(when initial-value? + `((with ,i = ,initial-value))) + ,@(when final-value? + `((with ,f = ,final-value) + (with ,done = nil))) + (,kwd ,var :next + (cond + ,@(when initial-value? + `(((first-time-p) ,i))) + ,@(when final-value? + `((,done (terminate)))) + ((atom ,l) + ,@(if final-value? + `((setf ,done t) ,f) + `((terminate)))) + (t (prog1 (car ,l) (setf ,l (funcall ,step-function ,l)))))))))) (defmacro-driver (FOR var IN-DIGITS-OF integer &optional RADIX (radix 10)) "Iterate `var` through the digits of `integer` in base `radix`, low-order first."