[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Microlight
- From: Philipp Janda <siffiejoe@...>
- Date: Fri, 21 Dec 2012 12:13:53 +0100
Am 20.12.2012 23:12, schrieb Jay Carlson:
On Dec 20, 2012, at 11:02 AM, Philipp Janda wrote:
And collect/icollect ([1], slightly altered) are actually surprisingly interesting:
icollect( {}, 1, pairs( t ) ) --> keys( t )
icollect( {}, 2, pairs( t ) ) --> values( t )
icollect( {}, 2, ipairs( t ) ) --> shallow_arraycopy( t )
icollect( {}, 1, io.lines( fname ) ) --> my @lines = <FILE>;
icollect( t1, 2, ipairs( t2 ) ) --> append( t1, t2 )
collect( {}, 1, 2, pairs( t ) ) --> shallow_tablecopy( t )
collect( {}, 1, 2, ipairs( t ) ) --> shallow_arraycopy( t )
collect( {}, 2, 1, ipairs( t ) ) --> invert( t ), makeset( t )
collect( t1, 1, 2, pairs( t2 ) ) --> extend( t1, t2 )
I really like this, but I hate numbers. Consider a function swap():
swap(1, 2)
-> return 2, 1
swap(1, 2, 3)
-> return 2, 1, 3
swap(1, nil)
-> return nil, 1
-- I'm ultra-paranoid. Would you ever want this to work?
swap(1)
-> error()
I thought it was a shame you can't write a no-memory iterator that applies swap() to another iterator's stepping. (You can't because the "next step" function is only called with *first* value it previously returned.)
That is not the (only) reason. Since you are wrapping another iterator,
you need to store its iterator function somewhere. Otherwise this would
work (without extra memory):
do
local function dup1( a, ... )
return a, a, ...
end
function dups1( f, s, var )
return function( st, v )
return dup1( f( st, v ) ) -- need f here!
end, s, var
end
end
-- icollect would always take the 2nd value
icollect( {}, pairs( t ) ) --> values( t )
icollect( {}, dups1( pairs( t ) ) ) --> keys( t )
Btw., the memory overhead is constant even for swaps, and you are
allocating a table anyway ...
Perhaps a wrapper calling "swap" per step could be called swaps()--it fits with pairs() and ipairs().
That way those examples could become
icollect({}, pairs( t ) ) -> keys(t)
icollect({}, swaps( pairs( t ) )) -> values(t)
collect({}, swaps( ipairs( t ) )) -> invert/Set(t)
or you could use:
icollect( {}, identity, pairs( t ) ) --> keys( t )
icollect( {}, swap, pairs( t ) ) --> values( t )
collect( {}, swap, ipairs( t ) ) --> invert( t )
*But*:
- the extra function would be mandatory
- some iterators (e.g. string.gmatch) can generate more than two values,
so we might need
collect( {}, swap_1_4_and_2_3, s:gmatch( "..." ) )
- using some arbitrary indices (even when it's 1 and 2) implicitly is
worse than passing numbers
- I find numbers pretty clear, and there is precedent (select,
table.insert, etc.), and you could make the numbers optional for a
common case (alternatively you could make the table optional)
On the pro side: You could actually use a for-loop in collect/icollect
instead of the tail recursive function.
Philipp