lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, Jan 19, 2009 at 06:37:35PM -0500, John Belmonte wrote:
>    [1] Challenge: implement Alex Mania's "appendud" example function
> in plain Lua while keeping the code easy to follow.  See
> <http://lua-users.org/lists/lua-l/2008-02/msg00243.html>.

If one doesn't care too much about syntactic sugar I think I can
come pretty close.

Well, there's an awful lot of apack/aunpack/pcall, so maybe not
super-easy to follow.

Btw, would it be cool with syntactic sugar for "application".
Something like apply@fun(a1, a2, ...) that just gets expanded to
apply(fun, a1, a2, ...). The idea is that a@b@c:d(x) is expand
to a@b@c.d(c, x) -> a@b(c.d, c, x) -> a(b, c.d, c, x). That
would make things like pcall@dofile(f), lazy@fib(n-1), and
finalize@tab:endupdate() much easier to read. And write. I often
write pcall(fun(a,b)) by mistake, but maybe that's just me.


-- pack and unpack argument lists
local function apack (...) return { n=select('#',...), ... } end
local function aunpack (a,i,j) j=j or a.n return unpack(a,i,j) end

-- protected scope with sequential finalizers
local function finalized (fun)
    local pcall = pcall
    return function (...) -- create wrapper
        local finalizers = {}
        local function add_finalizer (...)
            finalizers[#finalizers+1] = apack(...)
        end
        local presult = apack( pcall( fun, add_finalizer, ... ))
        local errors
        for i = #finalizers, 1, -1 do
            local ok, err = pcall( aunpack( finalizers[i] ))
            if not ok then
                if not errors then errors = {} end
                table.insert( errors, 1, tostring(err) )
            end
        end
        if not presult[1] then
            -- preserve custom error type if possible
            if not errors then error( presult[2], 0 ) end
            table.insert( errors, 1, tostring(presult[2]) )
        end
        if errors then
            error( table.concat(errors,'\n'), 0 )
        else
            return aunpack(presult, 2)
        end
    end
end

-- stubs
local tab = {
    beginupdate = function (this) print('tab.beginupdate') end;
    endupdate = function (this) print('tab.endupdate') end;
}
local ud = {
    lock = function (this) print('ud.lock') end;
    unlock = function (this) print('ud.unlock') end;
    1,2,3,4,5;
}

-- here we go
appendud = finalized(function (fin, tab, ud)
    tab:beginupdate() fin( tab.endupdate, tab )
    ud:lock() fin( ud.unlock, ud )
    for i = 1, #ud do
        tab[#tab+1] = ud[i]
    end
    return 7, 17
end)

-- test
print( appendud( tab, ud ))




-- 
Tommy Pettersson <ptp@lysator.liu.se>