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

Fix key and describe argument order of test #170

Closed
okamsn opened this issue Sep 10, 2023 · 5 comments
Closed

Fix key and describe argument order of test #170

okamsn opened this issue Sep 10, 2023 · 5 comments

Comments

@okamsn
Copy link
Owner

okamsn commented Sep 10, 2023

key should only be applied to the sequences, not the value to accumulate.

;; => (1 . 2)
(cl-find 1 '((1 . 2) (3 . 4)) :key #'car)

;; => ((1 . 2) (3 . 4))
(cl-member 1 '((1 . 2) (3 . 4)) :key #'car)

;; Should not error:
(loopy (with (coll '((1 . 2) (3 . 4))))
       (list i '(1 3))
       (adjoin i :key #'car))

Similarly, we should make sure that test also passes arguments as (VAR, VAL), which is the same order these arguments use in the command call ((adjoin VAR VAL)).

TODO: Check behavior of all functions that use key, such as cl-sort.

@okamsn okamsn added bug Something isn't working breaking changes labels Sep 10, 2023
@okamsn
Copy link
Owner Author

okamsn commented Oct 20, 2023

Turns out, the CLHS describes adjoin incorrectly. It describes :key as
being applied only to the sequence, as in functions like member and find,
but it actually applied to both arguments like in pushnew.

See:

Union also applies :key to both arguments.

Therefore, we do not seem to have a bug, but we should still check all uses and
better document the behaviors.

@okamsn
Copy link
Owner Author

okamsn commented Oct 20, 2023

Now, the questions become:

  1. Do we need :key if we already have a defined argument order for
    :test, which cl-lib has and seq lacks?
  2. Should the defined argument order should be (NEW-VAL EXISTING-VAL), as in
    things like cl-member and memq, or should it be (EXISTING-VAL NEW-VAL),
    as in things like seq-reduce, seq-union, seq-contains-p, and the loop
    commands?

As Loopy is an Emacs Lisp library and not a Common Lisp library, I think that it
makes sense to follow seq and not cl-lib, mainly because :key is redundant
and following the order of the loop commands is OK because it also follows
seq. Similarly, we chose to make the default test function equal, as done
in seq and some other Emacs Lisp functions, instead of eql, as done in
cl-lib.

@okamsn okamsn removed the bug Something isn't working label Oct 20, 2023
@okamsn
Copy link
Owner Author

okamsn commented Oct 21, 2023

The benefit of key is that we can apply the key function only once to the
tested argument when seeing if it is a member of the list. For example,

;; => ((a . 1) (b . 2) (c . 4))
(loopy (list i '((a . 1) (b . 2) (a . 3) (c . 4)))
       (adjoin i :key #'car))

should work similarly to

;; => ((a . 1) (b . 2) (c . 4))
(loopy (with (test-val))
       (list i '((a . 1) (b . 2) (a . 3) (c . 4)))
       (set test-val (car i))
       (adjoin i :test (lambda (seq-val _)
                         (equal (car seq-val)
                                test-val))))

, the membership test being something like

(cl-with-gensyms (test-val seq-val)
  `(cl-loop with ,test-val = (funcall ,key ,element)
            for ,seq-val in ,list
            thereis (funcall ,test (funcall ,key ,seq-val) ,test-val)))

.

okamsn added a commit that referenced this issue Oct 23, 2023
- Document the argument order of `test` as the first argument being the value
  from the sequence and the second argument being the tested item.  This is the
  same order as used by `seq-contains-p` and the opposite of `cl-member`.

  - Add `loopy--member-p`, used for tests for `adjoin`, `union`, and `nunion`.
    This function can be optimized during byte compilation via
    `loopy--member-p-comp` to become `member`, `memq`, or `memql` when possible,
    as done with `cl-member`.

- Simplify `loopy--plist-bind` into a wrapper around `cl-destructuring-bind`.

- Add `loopy--instr-let2*`, with works like `macroexp-let2*` except that it will
  also append variable-instructions to the result of the body as needed.  This
  will allow us to stop manually checking in each command whether we need to
  create a variable to hold a value.  Now, we create the variable is
  `macroexp-const-p` believes that the value would not be constant.

- Do not remove `key`.  The use of a separate argument allows us to optimize the
  transform function by only calling it once on the tested item
  during the execution of each command.  It is decided that re-creating
  this behavior with `set` and an ignored argument in the test function
  is too awkward.

See also issues #176, #170, and this PR.
@okamsn
Copy link
Owner Author

okamsn commented Oct 23, 2023

We have decided to keep key. This issue is fixed by PR #177.

okamsn added a commit that referenced this issue Oct 23, 2023
- Document the argument order of `test` as the first argument being the value
  from the sequence and the second argument being the tested item.  This is the
  same order as used by `seq-contains-p` and the opposite of `cl-member`.

  - Add `loopy--member-p`, used for tests for `adjoin`, `union`, and `nunion`.
    This function can be optimized during byte compilation via
    `loopy--member-p-comp` to become `member`, `memq`, or `memql` when possible,
    as done with `cl-member`.

- Simplify `loopy--plist-bind` into a wrapper around `cl-destructuring-bind`.

- Add `loopy--instr-let2*`, with works like `macroexp-let2*` except that it will
  also append variable-instructions to the result of the body as needed.  This
  will allow us to stop manually checking in each command whether we need to
  create a variable to hold a value.  Now, we create the variable is
  `macroexp-const-p` believes that the value would not be constant.

- Do not remove `key`.  The use of a separate argument allows us to optimize the
  transform function by only calling it once on the tested item
  during the execution of each command.  It is decided that re-creating
  this behavior with `set` and an ignored argument in the test function
  is too awkward.

- Remove mention of `init` keyword argument, which should have been deleted
  already.

- Update the CHANGELOG and correct some links.

- Update the README.

See also issues #176, #170, and this PR.
okamsn added a commit that referenced this issue Oct 23, 2023
- Document the argument order of `test` as the first argument being the value
  from the sequence and the second argument being the tested item.  This is the
  same order as used by `seq-contains-p` and the opposite of `cl-member`.

  - Add `loopy--member-p`, used for tests for `adjoin`, `union`, and `nunion`.
    This function can be optimized during byte compilation via
    `loopy--member-p-comp` to become `member`, `memq`, or `memql` when possible,
    as done with `cl-member`.

- Simplify `loopy--plist-bind` into a wrapper around `cl-destructuring-bind`.

- Add `loopy--instr-let2*`, with works like `macroexp-let2*` except that it will
  also append variable-instructions to the result of the body as needed.  This
  will allow us to stop manually checking in each command whether we need to
  create a variable to hold a value.  Now, we create the variable is
  `macroexp-const-p` believes that the value would not be constant.

- Do not remove `key`.  The use of a separate argument allows us to optimize the
  transform function by only calling it once on the tested item
  during the execution of each command.  It is decided that re-creating
  this behavior with `set` and an ignored argument in the test function
  is too awkward.

- Remove mention of `init` keyword argument, which should have been deleted
  already.

- Add examples for the common accumulation keyword arguments.

- Update the CHANGELOG and correct some links.

- Update the README.

See also issues #176, #170, and this PR.
okamsn added a commit that referenced this issue Oct 23, 2023
- Document the argument order of `test` as the first argument being the value
  from the sequence and the second argument being the tested item.  This is the
  same order as used by `seq-contains-p` and the opposite of `cl-member`.

  - Add `loopy--member-p`, used for tests for `adjoin`, `union`, and `nunion`.
    This function can be optimized during byte compilation via
    `loopy--member-p-comp` to become `member`, `memq`, or `memql` when possible,
    as done with `cl-member`.

- Simplify `loopy--plist-bind` into a wrapper around `cl-destructuring-bind`.

- Add `loopy--instr-let2*`, with works like `macroexp-let2*` except that it will
  also append variable-instructions to the result of the body as needed.  This
  will allow us to stop manually checking in each command whether we need to
  create a variable to hold a value.  Now, we create the variable is
  `macroexp-const-p` believes that the value would not be constant.

- Do not remove `key`.  The use of a separate argument allows us to optimize the
  transform function by only calling it once on the tested item
  during the execution of each command.  It is decided that re-creating
  this behavior with `set` and an ignored argument in the test function
  is too awkward.

- Remove mention of `init` keyword argument, which should have been deleted
  already.

- Add examples for the common accumulation keyword arguments.

- Update the CHANGELOG and correct some links.

- Update the README.

See also issues #176, #170, and this PR.
okamsn added a commit that referenced this issue Oct 23, 2023
- Document the argument order of `test` as the first argument being the value
  from the sequence and the second argument being the tested item.  This is the
  same order as used by `seq-contains-p` and the opposite of `cl-member`.

  - Add `loopy--member-p`, used for tests for `adjoin`, `union`, and `nunion`.
    This function can be optimized during byte compilation via
    `loopy--member-p-comp` to become `member`, `memq`, or `memql` when possible,
    as done with `cl-member`.

- Simplify `loopy--plist-bind` into a wrapper around `cl-destructuring-bind`.

- Add `loopy--instr-let2*`, with works like `macroexp-let2*` except that it will
  also append variable-instructions to the result of the body as needed.  This
  will allow us to stop manually checking in each command whether we need to
  create a variable to hold a value.  Now, we create the variable is
  `macroexp-const-p` believes that the value would not be constant.

- Do not remove `key`.  The use of a separate argument allows us to optimize the
  transform function by only calling it once on the tested item
  during the execution of each command.  It is decided that re-creating
  this behavior with `set` and an ignored argument in the test function
  is too awkward.

- Remove mention of `init` keyword argument, which should have been deleted
  already.

- Add examples for the common accumulation keyword arguments.

- Update the CHANGELOG and correct some links.

- Update the README.

See also issues #176, #170, and this PR #177.
@okamsn
Copy link
Owner Author

okamsn commented Oct 23, 2023

Done in #177.

@okamsn okamsn closed this as completed Oct 23, 2023
okamsn added a commit that referenced this issue Nov 10, 2023
… various clean-ups.

- Add `loopy--instr-let-var*`, `loopy--instr-let-const*`,
  `loopy--instr-let-var`, `loopy--instr-let-const`.  These macros are similar
  to `macroexp-let2*` in that the `const` versions try to pass constant values
  directly without creating a variable in the Loopy expansion.
  - Update `array`, `array-ref`, `cons`, `list`,  `list-ref`,
    `seq`, `seq-ref`, `seq-index`, `adjoin`, `union`, `nunion`

  - Don't update `numbers` until after we remove the non-keyword args.

- Replace some uses of `seq-let` with `cl-destructuring-bind`.

- Use `loopy--bind-main-body` in some places.

- Add some TODOs.

- Fix `list-ref` and `seq-ref` tests to not modify literal constant list.

- Make `loopy--find-start-by-end-dir-vals` return the test function.

- Add `:test` to `array`, `array-ref`, `sequence`, `sequence-index`, and
  `sequence-ref`.
  - When going up on lists, use `nthcdr` instead of `elt`.

- Add `sequence`, `sequence-ref`, `sequence-index`, `array`, and `array-ref`
  tests for `:downfrom` and `:upfrom` as needed.

See also topics #170, #176, #178, and this PR #180.
okamsn added a commit that referenced this issue Nov 10, 2023
… various clean-ups. (#180)

- Add `loopy--instr-let-var*`, `loopy--instr-let-const*`,
  `loopy--instr-let-var`, `loopy--instr-let-const`.  These macros are similar
  to `macroexp-let2*` in that the `const` versions try to pass constant values
  directly without creating a variable in the Loopy expansion.
  - Update `array`, `array-ref`, `cons`, `list`,  `list-ref`,
    `seq`, `seq-ref`, `seq-index`, `adjoin`, `union`, `nunion`

  - Don't update `numbers` until after we remove the non-keyword args.

- Replace some uses of `seq-let` with `cl-destructuring-bind`.

- Use `loopy--bind-main-body` in some places.

- Add some TODOs.

- Fix `list-ref` tests to not modify literal constant list.
- Fix `seq-ref` tests to not modify literal constant list.

- Make `loopy--find-start-by-end-dir-vals` return the test function.

- Add `:test` to `array`, `array-ref`, `sequence`, `sequence-index`, and
  `sequence-ref`.
  - When going up on lists, use `nthcdr` instead of `elt`.

- Add `sequence`, `sequence-ref`, `sequence-index`, `array`, and `array-ref`
  tests for `:downfrom` and `:upfrom` as needed.

See also topics #170, #176, #177, and this PR #180.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant