On 5/14/06, Axel Liljencrantz <[EMAIL PROTECTED]> wrote:
On 5/12/06, Beni Cherniavsky <[EMAIL PROTECTED]> wrote:
>
> Now, later in this thread you explain that all expansion in fish works as
> outer products.  For example::
>
>     echo %.(echo a\nb).(echo 1\n2)
>     echo {%,(echo a\nb),(echo 1\n2)},
>
> prints::
>
>     %.a.1 %.a.2 %.b.1 %.b.2
>     %, a, 1, %, a, 2, %, b, 1, %, b, 2,
>
> The first is obviously useful, for some of the examples you gave.  The
> second is questionable.

But sometimes useful: ``fgrep {-f,(ls *.words)}`` expands to ``fgrep
-f some.words -f more.words``

> I agree brace/command/variable expansions written side-by-side
> (``%.$v.(seq 2)``)
> should form an outer product, but inside braces, I think they should be 
joined,
> just like ``{%,{a,b},{1,2}}`` produces ``% a b 1 2``.
>
> What I'm driving at is that braces, not brackets, should be the
> joining operator
> that I talked about.

Thinking some more, I would like to consider the operators that are
frequently useful in a shell:

word_concat(a, 1) -> a1
list_concat([a b], [1 2]) -> [a b 1 2]
word_product([a b], [1 2]) -> [a1 a2 b1 b2]
list_product([a b], [1 2]) -> [a 1 a 2 b 1 b 2]
word_parallel([a b], [1 2]) -> [a1 b2]
list_parallel([a b], [1 2]) -> [a 1 b 2]

What we have now:

word_concat() doesn't really exist because words are built from items
like variable expansion that produce lists. In fish, it's a special
case of word_product().  [In bash, it's a special case of something
useless ;-).  In rc, it's a special case of word_parallel().]
The top level of a command line is list_concat() but it's not
availiable otherwise.
list_product() is availiable through braces but in a surprising way.
word_parallel() and list_parallel() are not availiable.

You can implement word_parallel() as::

   (paste -d "" (echo a\nb | psub) (echo 1\n2 | psub))

and list_parallel() as::

   (paste -d \n (echo a\nb | psub) (echo 1\n2 | psub))

Both are rarely needed, so I think this is good enough.

In this thread we want list_concat() inside array indexing.  Since
``$a[1 2]`` already expands into two words, it's not baseless.  It can
be implemented as::

   (printf '%s\n' 1 (seq 4 7))

but perhaps some direct syntax (not necessarily limited to indexing)
would be useful.

word_product() is extremely useful in simple cases like ``img(seq
5).png`` and it should remain availiable for such uses.

list_product() is sometimes useful (see fgrep example above).  You
could implement it with::

   (printf '%s' (echo a\nb)\n(echo 1\n2))\n

----

Note that all implementations using external commands suffer from
false splitting if any word contains newlines.  It's not a critical
usability bug like space-splitting was in bash but it still might be a
security bug in some situations.  Let's try reliable implementation
with arrays:

function vsub
   # should check that it's unused and register deletion
   # when calling job exits (see psub implementation)
   set -l name _vsub_(random)
   set -g $name $argv
   echo $name
end

# Such functions that return variable names could
# be used like ``$(vsub ...)`` if fish didn't catch it.
# This is useful for testing
function deref
   echo $$argv
end

function concat_arrays
   # variable indirection is also a product!
   vsub $$argv
end

function list_parallel
   concat_arrays (
       for i in (seq (count $$argv[1]))  # should take max or min or what?
           for v in $argv
               echo $$v[1][$i]
           end
       end)
end

function word_parallel
   concat_arrays (
       for i in (seq (count $$argv[1]))
           eval vsub (
               for v in $argv
                   echo -n \${$v}\[$i\]
               end)
       end)
end

So I hacked perlish references int the flat data structures of fish.
May God forgive me ;-\.
No, I do NOT think this is the right way.  But I do want robust
operations on word lists.
Ideas?

--
Beni Cherniavsky <[EMAIL PROTECTED]>, who can only read email on weekends.
Governments are like kernels - everything possible should be done in user space.

Reply via email to