gpt4 book ai didi

lua - 在 Lua 中实现延迟执行?

转载 作者:行者123 更新时间:2023-12-04 06:08:57 25 4
gpt4 key购买 nike

我一直想知道是否有可能在 Lua 中实现延迟执行,.NET Linq 风格,只是为了好玩。

在 .NET 中,我们可以创建一系列称为 IEnumerable 的元素。然后可以通过各种方式过滤这些元素,例如 map/reduce (Select(predicate), Where(predicate)),但只执行这些过滤器的计算当您枚举 IEnumerable 时 - 它被推迟。

我一直在尝试在 Lua 中实现类似的功能,尽管我对 Lua 很生疏并且有一段时间没有接触它了。我想避免使用已经为我执行此操作的库,因为我希望能够尽可能在纯 Lua 中执行此操作。

我的想法是也许可以使用协程..

Enumerable = {

-- Create an iterator and utilize it to iterate
-- over the Enumerable. This should be called from
-- a "for" loop.
each = function(self)
local itr = Enumerable.iterator(self)
while coroutine.status(itr) ~= 'dead' do
return function()
success, yield = coroutine.resume(itr)
if success then
return yield
else
error(1, "error while enumerating")
end
end
end
end,

-- Return an iterator that can be used to iterate
-- over the elements in this collection.
iterator = function(self)
return coroutine.create(function()
for i = 1, #self do
coroutine.yield(self[i])
end
end)
end
}


tbl = {1, 2, 3}

for element in Enumerable.each(tbl) do
print(element)
end

table.insert(tbl, 4)

for element in Enumerable.each(tbl) do
print(element)
end

然而,在写完这篇文章后,我意识到这并不是真正的延迟执行。这只是使用绿色线程的美化迭代器。

我正在尝试实现它以更好地理解函数式编程的工作原理,使用我已经了解的语言。

想法?

最佳答案

在 Lua 中获得延迟执行的方法是使用函数。您需要从

Where( x > 1 )

Where(function(x) return x > 1 end)

一个完整的工作示例将类似于以下代码。为了简单起见,我省略了链接语法。

-- A stream is a function that returns a different value each time you call it
-- and returns nil after the last value is generated. Its a bit like what ipairs returns.

-- Receives a list, returns a stream that yields its values
function Each(xs)
return coroutine.wrap(function()
for _, x in ipairs(xs) do
coroutine.yield(x)
end
end)
end

-- Receives a stream and returns a new stream, filtered by a predicate
function Where(input, pred)
return coroutine.wrap(function()
for x in input do
if pred(x) then
coroutine.yield(x)
end
end
end)
end

local ys = {1,2,3,4,5}
for y in Where(Each(ys), function(x) return x <= 2 end) do
print(y)
end

如果您想知道如何处理链接,方法是让“流”类型成为具有方法的对象而不是普通函数。

local Stream = {}

-- The low level stream constructor receives a generator function
-- similar to the one coroutine.wrap would return. You could change the API
-- to something returning multiple values, like ipairs does.
function Stream:new(gen)
local stream = { _next = gen}
setmetatable(stream, self)
self.__index = self
return stream
end

-- Receives a predicate and returns a filtered Stream
function Stream:Where(pred)
return Stream:new(coroutine.wrap(function()
for x in self._next do
if pred(x) then
coroutine.yield(x)
end
end
end))
end


function Stream:Length()
local n = 0
for _ in self._next do
n = n + 1
end
return n
end

function Each(list)
return Stream:new(coroutine.wrap(function()
for _, x in ipairs(list) do
coroutine.yield(x)
end
end))
end

local ys = {10, 20, 30, 40}
print( Each(ys):Where(function(x) return x <= 20 end):Length() )

协程更多的是让您以一种直接的方式编写协作函数,而无需将其中一个函数“颠倒过来”。例如,完全可以在不使用协程的情况下为列表实现迭代器:

-- if you try to code ipairs on your own, without coroutines
-- it might look a bit like this
function Each(xs)
local i=1
return function()
if i <= # xs then
local x = xs[i]
i = i + 1
return x
else
return nil
end
end
end

由于我们返回一个“getnext”函数,我们一次只能获取一个元素。然而,我们不得不“炸毁”for 循环,将其变成 ifs 并手动更新循环计数器。我们还需要明确地跟踪所有迭代状态。在这种情况下,它只是循环计数器,但在具有递归的协程中,您需要保留一个堆栈,如果协程在其主体中有多个 yield,那么您需要一些状态标志来完成程序计数器的工作。

关于lua - 在 Lua 中实现延迟执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24518121/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com