Print

Print


To be clear, I'm perfectly ready to keep the old interface. I was
mostly concentrating on the implementation, and some functions
appeared more natural than the existing ones in that context.

> > Then there is the issue of l3candidates, which I have not
> > re-programmed yet, as well as the quicksort defined in l3prg.dtx
>
> one step at a time i'd say.

I meant that there are some \seq_from_clist and \clist_from_seq
functions in l3candidates which will have to be rewritten, and a
\seq_quicksort, or something like that, which I haven't looked at. I'm
_definitely not_ rewriting l3prg.dtx :).

>  > - I don't like the fact that \seq_(g)pop return its value locally, so
>  > I changed which functions are provided there to \seq_pop_with:Nn <seq>
>  > {<assignment code>}.
>
> Im not sure here.
>
>  - the general design principle is that all functions that get values from
>    some data structure *always* store them *locally* in a variable.
>
>  - the data structure itself could be local or global and a manipulation of
>    the structure could then be local or global too.

Is there any example of data structure other than seq or prop?


> On the other hand popping + using the value is a quite common usage, so to
> have to always write
>
>   \seq_pop_left_with:Nn \l_foo_seq {\tl_set:Nn \l_bar_tl}
>
> instead of
>
>   \seq_pop:NN \l_foo_seq \l_bar_tl

I see your point. Then perhaps renaming \seq_pop_left_with:Nn to
\seq_pop_left_do:Nn, and leaving \seq_pop:NN as it is could make
sense. Then if we just want to remove the left-most element and apply
some function onto it, we can do

\seq_pop_left_do:Nn \l_foo_seq {\foo:nn {<arg1>}}

and to get a global return value we would do

\seq_pop_left_do:Nn \l_foo_seq {\tl_gset:Nn \g_foo_tl}

Basically, I'm just making an auxiliary function available to the user.

> now having written that I noticed that it isn't true, this is violated in
> l3prop where there are gget functions for key values, so hmmm ... still I
> tend towards the rule above I guess

I think that you are right: there should be a \..._pop_left:NN, which
does something consistent between the various data structures.
Choosing local return values is as good as anything.

> not sure what you mean here. clearly if you loop directly over a sequence
> then using mapping is preferable, but often when you do one element at a time the
> actions are complex so that they don't quite fit into a mapping function

I guess I was just stating the obvious to a TeX programmer: getting
one element in the seq takes a time linear in the length of the seq.
I.e., it is not much faster than mapping on every element. In terms of
efficiency, it is _much_ better to do

\seq_map_inline:Nn \l_foo_seq { <complicated code using #1 spanning
several lines> }

than

\bool_until_do:nn {\seq_if_empty_p:N \l_foo_seq} {
    \seq_pop_left:NN \l_foo_seq \l_foo_tl
    <same complicated code using \l_foo_tl>
}

although the latter is probably clearer.

>  > - I expect the pop_right functions to be much faster for large
>  > sequences than simply storing the elements one by one.
>
> ???

Implementation detail. The naive way of doing things on the right-most
element of the sequence is to remove elements one by one, and store
them in a scratch register, until the last element is reached. That
will be quadratic, and it turned out to be particularly tricky to get
the linear version right. Anyways, unimportant here.


>  > - I'd like every "..._map_function:NN" to become
>  > "..._map_function:Nn", i.e. allow mapping several tokens at a time. It
>
> Personally I don't find this very intuitive; if you map a function you map a
> function name and that would mean N.  Besides you would lose the ability to
> map a constructed function name ie "c" though that is something you would seldom
> need I guess.

My initial application was to be able to map a function with two
arguments on two seq <a> and <b> at the same time. First I zipped the
two seq into one seq whose item each have the form {<a_i>}{<b_i>}.
Then I could map _expandably_

\seq_map_function:Nn \l_foo_zipped_seq {\exp_after:wN \foo_func:nn \use:n}

where the \use:n unbraces its argument. Not a very convincing use.

But Lars Madsen's examples with { \foo_func:nn {arg1} } are better.

> I would rather do
>
>  \cs_new:Npn \map_func:n #1 {<some tokens> \func:n #1}
>  ...map_function:NN \l_foo_seq \map_func:n

That would be better as

...map_inline:Nn \l_foo_seq {<some tokens> \func:n {#1}}

The key here is expandability. When it is not needed, map_inline:Nn
and map_variable:NNn fit the bill nicely. The best might be to leave
both the :NN and :Nn variants, synonyms of each other, hence taking
little of TeX's memory.


There is also the question of whether removing an elements once/all
copies of it should be named as in l3clist or l3tl:

   \clist_remove_element:Nn
   \tl_remove_all_in:Nn
   \tl_remove_in:Nn

I'd go for the tl version.

Regards,
-- Bruno