Skip to content

Commit 7d76cee

Browse files
authored
Review evaluation of keyword arguments during expansion and run time. (#211)
- Make `close` in `iter` evaluable. Make it evaluated at the beginning. - Make `on-failure` in `find` evaluated at the beginning. Closes issue #210. See this PR #211.
1 parent 64a95bc commit 7d76cee

File tree

6 files changed

+198
-60
lines changed

6 files changed

+198
-60
lines changed

CHANGELOG.md

+11-3
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,15 @@ This document describes the user-facing changes to Loopy.
4242

4343
- Make `sequence-index` the default name and `seq-index` an alias ([#126, #206]).
4444

45-
- Allow the `unique` keyword argument of the commands `map` and `map-ref` to be
46-
evaluable at run time, instead of just checked at compile time ([#209]).
45+
- Review when the values of keyword arguments are taken and used ([#210]):
46+
- Make the `close` keyword argument of the `iter` command able to be evaluated
47+
during run time ([#211]). It was previously only used during macro expansion.
48+
- Make the `close` keyword argument of the `iter` command evaluated at the
49+
start of the loop to be consistent with other commands ([#211]).
50+
- Make the `on-failure` keyword argument of the `find` command evaluated at the
51+
start of the loop to be consistent with other commands ([#211]).
52+
- Allow the `unique` keyword argument of the commands `map` and `map-ref` to be
53+
evaluable at run time, instead of just checked at compile time ([#209]).
4754

4855
### Improvements
4956

@@ -60,7 +67,8 @@ This document describes the user-facing changes to Loopy.
6067
[#206]: https://github.com/okamsn/loopy/pull/206
6168
[#207]: https://github.com/okamsn/loopy/pull/207
6269
[#209]: https://github.com/okamsn/loopy/pull/209
63-
70+
[#210]: https://github.com/okamsn/loopy/issues/210
71+
[#211]: https://github.com/okamsn/loopy/pull/211
6472

6573
## 0.13.0
6674

README.org

+9-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,15 @@ please let me know.
3939
list of built-in aliases in the future. They can still be added to the
4040
list of known aliases using ~loopy-defalias~. See the changelog for more
4141
information.
42-
- The =:unique= keyword argument of the =map= and =map-ref= commands can now
43-
be evaluable at run time, similar to most other keyword arguments.
42+
- Improved consistency of some keyword arguments:
43+
- The =:unique= keyword argument of the =map= and =map-ref= commands can now
44+
be evaluable at run time.
45+
- The =:close= argument of the =iter= command is now evaluable, instead of
46+
only being used during macro expansion.
47+
- The =:close= argument of the =iter= command is now evaluated at the
48+
beginning of the loop.
49+
- The =:on-failure= argument of the =find= command is now evaluated at the
50+
beginning of the loop.
4451
- Version 0.13.0:
4552
- The deprecated =:init= keyword argument has been removed. Use the =with=
4653
special macro argument instead.

doc/loopy-doc.org

+37-6
Original file line numberDiff line numberDiff line change
@@ -1507,13 +1507,17 @@ loop. This restriction allows for producing more efficient code.
15071507
holds the value yielded by the iterator. The loop ends when the iterator
15081508
finishes.
15091509

1510+
=close= is whether the generator should be closed via ~iter-close~ after the
1511+
loop ends. The default is ~t~. Note that Emacs will eventually close
1512+
un-closed, un-reachable generators during garbage collection. To be
1513+
consistent with other commands, =close= is evaluated at the start of the loop,
1514+
even though it's value is only used after the loop finishes.
1515+
15101516
=yield-result= is the optional second argument to the function ~iter-next~,
15111517
which is the value of ~iter-yield~ in the iterator (not to be confused with
1512-
the value yielded by calling ~iter-next~).
1513-
1514-
=close= is whether the generator should be closed via ~iter-close~ after the
1515-
loop ends. The default is ~t~. Note that Emacs will eventually close
1516-
un-closed, un-reachable generators during garbage collection.
1518+
the value yielded by calling ~iter-next~). Unlike =close=, which is evaluated
1519+
once, =yield-result= is an expression which is substituted into the loop body.
1520+
Therefore, =yield-result= can be used to repeatedly call functions.
15171521

15181522
For efficiency, when possible, =VAR= is bound to the yielded value before each
15191523
step of the loop, which is used to detect whether the iterator signals that it
@@ -1526,6 +1530,7 @@ loop. This restriction allows for producing more efficient code.
15261530

15271531
#+begin_src emacs-lisp
15281532
;; With var:
1533+
;;
15291534
;; => ((1 . 4) (2 . 5) (3 . 6))
15301535
(loopy (with (iter-maker (iter-lambda (x)
15311536
(while x
@@ -1535,6 +1540,7 @@ loop. This restriction allows for producing more efficient code.
15351540
(collect (cons i j)))
15361541

15371542
;; Without var:
1543+
;;
15381544
;; => (1 2 3)
15391545
(loopy (iter (funcall (iter-lambda ()
15401546
;; These yielded values are all ignored.
@@ -1543,6 +1549,21 @@ loop. This restriction allows for producing more efficient code.
15431549
(iter-yield 'third-yield))))
15441550
(set i 1 (1+ i))
15451551
(collect i))
1552+
1553+
;; Using `yield-result':
1554+
;;
1555+
;; => (3 2 1)
1556+
(loopy (with (yield-results nil))
1557+
(set i 1 (1+ i))
1558+
(iter (funcall (iter-lambda ()
1559+
;; The value from the expression specified by
1560+
;; `:yield-result' is `push'-ed:
1561+
(push (iter-yield 'first-yield) yield-results)
1562+
(push (iter-yield 'second-yield) yield-results)
1563+
(push (iter-yield 'third-yield) yield-results)))
1564+
;; Note that the value of `i' evaluated each time:
1565+
:yield-result i)
1566+
(finally-return yield-results))
15461567
#+end_src
15471568

15481569
#+ATTR_TEXINFO: :tag Warning
@@ -2124,7 +2145,7 @@ source sequences.
21242145
=EXPR=. If =by= is non-nil (default: 1), then move to the next n-th element
21252146
during each iteration. This command is a special case of the =substream=
21262147
command (described below), setting =VAR= to the first element of each
2127-
substream. For more information, see the command =substream=.
2148+
substream. For more information on streams, see the command =substream=.
21282149

21292150
This command also has the alias =streaming=.
21302151

@@ -3397,6 +3418,9 @@ Sequence accumulation commands are used to join lists (such as =union= and
33973418
normal failure and =VAR= will be set to the value of =ON-FAILURE=, if
33983419
provided.
33993420

3421+
To be consistent with other commands, =ON-FAILURE= is evaluated at the
3422+
start of the loop, even though that is not necessarily where it is used.
3423+
34003424
#+BEGIN_SRC emacs-lisp
34013425
;; => (13 (1 2))
34023426
(loopy (list i '(1 2 3 4 5 6 7 8))
@@ -3420,6 +3444,13 @@ Sequence accumulation commands are used to join lists (such as =union= and
34203444
;; => nil
34213445
(loopy (list i '(1 2 3 4 5 6))
34223446
(find nil (> i 3) :on-failure 27))
3447+
3448+
;; Value of `:on-failure' gotten at the start of the loop:
3449+
;; => 27
3450+
(loopy (with (on-fail 27))
3451+
(list i '(1 2 3))
3452+
(set on-fail 33)
3453+
(find i (> i 4) :on-failure on-fail))
34233454
#+END_SRC
34243455

34253456
*** Optimizing Accumulations

doc/loopy.texi

+41-10
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ You should keep in mind that commands are evaluated in order. This means that
705705
attempting something like the below example might not do what you expect, as @samp{i}
706706
is assigned a value from the list after collecting @samp{i} into @samp{coll}.
707707

708-
@float Listing,orgfa9540f
708+
@float Listing,orgcd9d132
709709
@lisp
710710
;; => (nil 1 2)
711711
(loopy (collect coll i)
@@ -887,7 +887,7 @@ the flag @samp{dash} provided by the package @samp{loopy-dash}.
887887

888888
Below are two examples of destructuring in @code{cl-loop} and @code{loopy}.
889889

890-
@float Listing,orgb706e77
890+
@float Listing,orgf148300
891891
@lisp
892892
;; => (1 2 3 4)
893893
(cl-loop for (i . j) in '((1 . 2) (3 . 4))
@@ -902,7 +902,7 @@ Below are two examples of destructuring in @code{cl-loop} and @code{loopy}.
902902
@caption{Destructuring values in a list.}
903903
@end float
904904

905-
@float Listing,orgcc60e47
905+
@float Listing,orgff97ac8
906906
@lisp
907907
;; => (1 2 3 4)
908908
(cl-loop for elem in '((1 . 2) (3 . 4))
@@ -1668,13 +1668,17 @@ iterator object produced by a calling a generator function. If given, @samp{VAR
16681668
holds the value yielded by the iterator. The loop ends when the iterator
16691669
finishes.
16701670

1671+
@samp{close} is whether the generator should be closed via @code{iter-close} after the
1672+
loop ends. The default is @code{t}. Note that Emacs will eventually close
1673+
un-closed, un-reachable generators during garbage collection. To be
1674+
consistent with other commands, @samp{close} is evaluated at the start of the loop,
1675+
even though it's value is only used after the loop finishes.
1676+
16711677
@samp{yield-result} is the optional second argument to the function @code{iter-next},
16721678
which is the value of @code{iter-yield} in the iterator (not to be confused with
1673-
the value yielded by calling @code{iter-next}).
1674-
1675-
@samp{close} is whether the generator should be closed via @code{iter-close} after the
1676-
loop ends. The default is @code{t}. Note that Emacs will eventually close
1677-
un-closed, un-reachable generators during garbage collection.
1679+
the value yielded by calling @code{iter-next}). Unlike @samp{close}, which is evaluated
1680+
once, @samp{yield-result} is an expression which is substituted into the loop body.
1681+
Therefore, @samp{yield-result} can be used to repeatedly call functions.
16781682

16791683
For efficiency, when possible, @samp{VAR} is bound to the yielded value before each
16801684
step of the loop, which is used to detect whether the iterator signals that it
@@ -1687,6 +1691,7 @@ This command also has the name @samp{iterating}.
16871691

16881692
@lisp
16891693
;; With var:
1694+
;;
16901695
;; => ((1 . 4) (2 . 5) (3 . 6))
16911696
(loopy (with (iter-maker (iter-lambda (x)
16921697
(while x
@@ -1696,6 +1701,7 @@ This command also has the name @samp{iterating}.
16961701
(collect (cons i j)))
16971702
16981703
;; Without var:
1704+
;;
16991705
;; => (1 2 3)
17001706
(loopy (iter (funcall (iter-lambda ()
17011707
;; These yielded values are all ignored.
@@ -1704,6 +1710,21 @@ This command also has the name @samp{iterating}.
17041710
(iter-yield 'third-yield))))
17051711
(set i 1 (1+ i))
17061712
(collect i))
1713+
1714+
;; Using `yield-result':
1715+
;;
1716+
;; => (3 2 1)
1717+
(loopy (with (yield-results nil))
1718+
(set i 1 (1+ i))
1719+
(iter (funcall (iter-lambda ()
1720+
;; The value from the expression specified by
1721+
;; `:yield-result' is `push'-ed:
1722+
(push (iter-yield 'first-yield) yield-results)
1723+
(push (iter-yield 'second-yield) yield-results)
1724+
(push (iter-yield 'third-yield) yield-results)))
1725+
;; Note that the value of `i' evaluated each time:
1726+
:yield-result i)
1727+
(finally-return yield-results))
17071728
@end lisp
17081729

17091730
@quotation Warning
@@ -2306,7 +2327,7 @@ Iterate through the elements for the stream
23062327
@samp{EXPR}. If @samp{by} is non-nil (default: 1), then move to the next n-th element
23072328
during each iteration. This command is a special case of the @samp{substream}
23082329
command (described below), setting @samp{VAR} to the first element of each
2309-
substream. For more information, see the command @samp{substream}.
2330+
substream. For more information on streams, see the command @samp{substream}.
23102331

23112332
This command also has the alias @samp{streaming}.
23122333

@@ -3678,6 +3699,9 @@ If the loop is left early and @samp{TEST} was never non-nil, this is the same as
36783699
normal failure and @samp{VAR} will be set to the value of @samp{ON-FAILURE}, if
36793700
provided.
36803701

3702+
To be consistent with other commands, @samp{ON-FAILURE} is evaluated at the
3703+
start of the loop, even though that is not necessarily where it is used.
3704+
36813705
@lisp
36823706
;; => (13 (1 2))
36833707
(loopy (list i '(1 2 3 4 5 6 7 8))
@@ -3701,6 +3725,13 @@ provided.
37013725
;; => nil
37023726
(loopy (list i '(1 2 3 4 5 6))
37033727
(find nil (> i 3) :on-failure 27))
3728+
3729+
;; Value of `:on-failure' gotten at the start of the loop:
3730+
;; => 27
3731+
(loopy (with (on-fail 27))
3732+
(list i '(1 2 3))
3733+
(set on-fail 33)
3734+
(find i (> i 4) :on-failure on-fail))
37043735
@end lisp
37053736
@end table
37063737

@@ -4654,7 +4685,7 @@ using the @code{let*} special form.
46544685
This method recognizes all commands and their aliases in the user option
46554686
@code{loopy-aliases}.
46564687

4657-
@float Listing,orgab882ee
4688+
@float Listing,org7411b6a
46584689
@lisp
46594690
;; => ((1 2 3) (-3 -2 -1) (0))
46604691
(loopy-iter (arg accum-opt positives negatives other)

0 commit comments

Comments
 (0)