Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review evaluation of keyword arguments during run time and expansion time. #211

Merged
merged 1 commit into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,15 @@ This document describes the user-facing changes to Loopy.

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

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

### Improvements

Expand All @@ -60,7 +67,8 @@ This document describes the user-facing changes to Loopy.
[#206]: https://github.com/okamsn/loopy/pull/206
[#207]: https://github.com/okamsn/loopy/pull/207
[#209]: https://github.com/okamsn/loopy/pull/209

[#210]: https://github.com/okamsn/loopy/issues/210
[#211]: https://github.com/okamsn/loopy/pull/211

## 0.13.0

Expand Down
11 changes: 9 additions & 2 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ please let me know.
list of built-in aliases in the future. They can still be added to the
list of known aliases using ~loopy-defalias~. See the changelog for more
information.
- The =:unique= keyword argument of the =map= and =map-ref= commands can now
be evaluable at run time, similar to most other keyword arguments.
- Improved consistency of some keyword arguments:
- The =:unique= keyword argument of the =map= and =map-ref= commands can now
be evaluable at run time.
- The =:close= argument of the =iter= command is now evaluable, instead of
only being used during macro expansion.
- The =:close= argument of the =iter= command is now evaluated at the
beginning of the loop.
- The =:on-failure= argument of the =find= command is now evaluated at the
beginning of the loop.
- Version 0.13.0:
- The deprecated =:init= keyword argument has been removed. Use the =with=
special macro argument instead.
Expand Down
43 changes: 37 additions & 6 deletions doc/loopy-doc.org
Original file line number Diff line number Diff line change
Expand Up @@ -1507,13 +1507,17 @@ loop. This restriction allows for producing more efficient code.
holds the value yielded by the iterator. The loop ends when the iterator
finishes.

=close= is whether the generator should be closed via ~iter-close~ after the
loop ends. The default is ~t~. Note that Emacs will eventually close
un-closed, un-reachable generators during garbage collection. To be
consistent with other commands, =close= is evaluated at the start of the loop,
even though it's value is only used after the loop finishes.

=yield-result= is the optional second argument to the function ~iter-next~,
which is the value of ~iter-yield~ in the iterator (not to be confused with
the value yielded by calling ~iter-next~).

=close= is whether the generator should be closed via ~iter-close~ after the
loop ends. The default is ~t~. Note that Emacs will eventually close
un-closed, un-reachable generators during garbage collection.
the value yielded by calling ~iter-next~). Unlike =close=, which is evaluated
once, =yield-result= is an expression which is substituted into the loop body.
Therefore, =yield-result= can be used to repeatedly call functions.

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

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

;; Without var:
;;
;; => (1 2 3)
(loopy (iter (funcall (iter-lambda ()
;; These yielded values are all ignored.
Expand All @@ -1543,6 +1549,21 @@ loop. This restriction allows for producing more efficient code.
(iter-yield 'third-yield))))
(set i 1 (1+ i))
(collect i))

;; Using `yield-result':
;;
;; => (3 2 1)
(loopy (with (yield-results nil))
(set i 1 (1+ i))
(iter (funcall (iter-lambda ()
;; The value from the expression specified by
;; `:yield-result' is `push'-ed:
(push (iter-yield 'first-yield) yield-results)
(push (iter-yield 'second-yield) yield-results)
(push (iter-yield 'third-yield) yield-results)))
;; Note that the value of `i' evaluated each time:
:yield-result i)
(finally-return yield-results))
#+end_src

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

This command also has the alias =streaming=.

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

To be consistent with other commands, =ON-FAILURE= is evaluated at the
start of the loop, even though that is not necessarily where it is used.

#+BEGIN_SRC emacs-lisp
;; => (13 (1 2))
(loopy (list i '(1 2 3 4 5 6 7 8))
Expand All @@ -3420,6 +3444,13 @@ Sequence accumulation commands are used to join lists (such as =union= and
;; => nil
(loopy (list i '(1 2 3 4 5 6))
(find nil (> i 3) :on-failure 27))

;; Value of `:on-failure' gotten at the start of the loop:
;; => 27
(loopy (with (on-fail 27))
(list i '(1 2 3))
(set on-fail 33)
(find i (> i 4) :on-failure on-fail))
#+END_SRC

*** Optimizing Accumulations
Expand Down
51 changes: 41 additions & 10 deletions doc/loopy.texi
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ You should keep in mind that commands are evaluated in order. This means that
attempting something like the below example might not do what you expect, as @samp{i}
is assigned a value from the list after collecting @samp{i} into @samp{coll}.

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

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

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

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

@samp{close} is whether the generator should be closed via @code{iter-close} after the
loop ends. The default is @code{t}. Note that Emacs will eventually close
un-closed, un-reachable generators during garbage collection. To be
consistent with other commands, @samp{close} is evaluated at the start of the loop,
even though it's value is only used after the loop finishes.

@samp{yield-result} is the optional second argument to the function @code{iter-next},
which is the value of @code{iter-yield} in the iterator (not to be confused with
the value yielded by calling @code{iter-next}).

@samp{close} is whether the generator should be closed via @code{iter-close} after the
loop ends. The default is @code{t}. Note that Emacs will eventually close
un-closed, un-reachable generators during garbage collection.
the value yielded by calling @code{iter-next}). Unlike @samp{close}, which is evaluated
once, @samp{yield-result} is an expression which is substituted into the loop body.
Therefore, @samp{yield-result} can be used to repeatedly call functions.

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

@lisp
;; With var:
;;
;; => ((1 . 4) (2 . 5) (3 . 6))
(loopy (with (iter-maker (iter-lambda (x)
(while x
Expand All @@ -1696,6 +1701,7 @@ This command also has the name @samp{iterating}.
(collect (cons i j)))

;; Without var:
;;
;; => (1 2 3)
(loopy (iter (funcall (iter-lambda ()
;; These yielded values are all ignored.
Expand All @@ -1704,6 +1710,21 @@ This command also has the name @samp{iterating}.
(iter-yield 'third-yield))))
(set i 1 (1+ i))
(collect i))

;; Using `yield-result':
;;
;; => (3 2 1)
(loopy (with (yield-results nil))
(set i 1 (1+ i))
(iter (funcall (iter-lambda ()
;; The value from the expression specified by
;; `:yield-result' is `push'-ed:
(push (iter-yield 'first-yield) yield-results)
(push (iter-yield 'second-yield) yield-results)
(push (iter-yield 'third-yield) yield-results)))
;; Note that the value of `i' evaluated each time:
:yield-result i)
(finally-return yield-results))
@end lisp

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

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

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

To be consistent with other commands, @samp{ON-FAILURE} is evaluated at the
start of the loop, even though that is not necessarily where it is used.

@lisp
;; => (13 (1 2))
(loopy (list i '(1 2 3 4 5 6 7 8))
Expand All @@ -3701,6 +3725,13 @@ provided.
;; => nil
(loopy (list i '(1 2 3 4 5 6))
(find nil (> i 3) :on-failure 27))

;; Value of `:on-failure' gotten at the start of the loop:
;; => 27
(loopy (with (on-fail 27))
(list i '(1 2 3))
(set on-fail 33)
(find i (> i 4) :on-failure on-fail))
@end lisp
@end table

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

@float Listing,orgab882ee
@float Listing,org7411b6a
@lisp
;; => ((1 2 3) (-3 -2 -1) (0))
(loopy-iter (arg accum-opt positives negatives other)
Expand Down
Loading
Loading