Lua DSL 还是巧妙的闭包?

发布于 2025-01-04 01:37:46 字数 1485 浏览 1 评论 0原文

我正在尝试使用 Lua 并尝试实现一些列表处理逻辑。我不确定我是否真正掌握了协程和匿名函数的力量,但我正在尝试。我知道这些东西在其他脚本语言(如 Ruby/Groovy/Javascript)中是如何工作的,并且我想在 Lua 中做一些同样聪明的事情。这是我想出的例子:

model = { { player = "Cliff", age = 35, gender = "male" }, { player = "Ally", age = 36, gender = "female" }, { player = "Jasmine", age = 13, gender = "female" }, { player = "Lauren", age = 6.5, gender = "female" } }

function allplayers()
    return coroutine.create(function()
        for idx, each in ipairs(model) do
            coroutine.yield(idx, each)
        end
    end)
end

function handlePlayers(source)
    local status, idx, each = coroutine.resume(source)
    while each do
        print(idx, each.player)
        status, idx, each = coroutine.resume(source)
    end
end

function having(source, predicate)
    return coroutine.create(function()
        local status, idx, each = coroutine.resume(source)
        while each do
            if predicate(each)  then
                coroutine.yield(idx, each)
            end
            status, idx, each = coroutine.resume(source)
        end
    end)
end

handlePlayers(having(allplayers(), function(each) return each.age < 30 end))

理想情况下,我希望能够编写如下代码:

allplayers(having(function(each) return each.age < 30 end))

甚至更好:

allplayers(having({each.age < 30 }))

产生相同的输出,但我不太清楚如何或即使这可以完成吧。我上面的内容对于所有迭代和循环等等来说似乎太多余了。有没有更绝妙的方法来做到这一点? (天哪,我怀念用 Groovy 编码,因为总有一种更绝妙的方式来做某事......)

I'm cutting my teeth with Lua and trying to implement some list processing logic. I'm not sure if I truly grasp the power of coroutines and anonymous functions but I'm trying. I know how these things work in other scripting languages like Ruby/Groovy/Javascript and I'm wanting to do something equally as clever in Lua. Here's what I've come up with as an example:

model = { { player = "Cliff", age = 35, gender = "male" }, { player = "Ally", age = 36, gender = "female" }, { player = "Jasmine", age = 13, gender = "female" }, { player = "Lauren", age = 6.5, gender = "female" } }

function allplayers()
    return coroutine.create(function()
        for idx, each in ipairs(model) do
            coroutine.yield(idx, each)
        end
    end)
end

function handlePlayers(source)
    local status, idx, each = coroutine.resume(source)
    while each do
        print(idx, each.player)
        status, idx, each = coroutine.resume(source)
    end
end

function having(source, predicate)
    return coroutine.create(function()
        local status, idx, each = coroutine.resume(source)
        while each do
            if predicate(each)  then
                coroutine.yield(idx, each)
            end
            status, idx, each = coroutine.resume(source)
        end
    end)
end

handlePlayers(having(allplayers(), function(each) return each.age < 30 end))

Ideally I'd like to be able to write code like:

allplayers(having(function(each) return each.age < 30 end))

or even better:

allplayers(having({each.age < 30 }))

to produce the same output but I can't quite get my head around how or even if this can be done. What I have above seems way too redundant with all the iteration and loops and all. Is there a groovier way to do this? (Boy I miss coding in Groovy, because there was always a groovier way to do something...)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

や三分注定 2025-01-11 01:37:46

如果不需要重用过滤后的结果,请考虑迭代器:

model = {
  { player = "Cliff", age = 35, gender = "male" },
  { player = "Ally", age = 36, gender = "female" },
  { player = "Jasmine", age = 13, gender = "female" },
  { player = "Lauren", age = 6.5, gender = "female" }
}

function model:having(predicate)
    local index = 0 
    return function()
        while true do
            index = index + 1
            if index > #self then break end
            if predicate(self[index]) then return self[index] end
        end
    end
end

for item in model:having(function(m) return m.age < 30 end) do
    print(item.player)
end

If you don't need to reuse the filtered result, consider an iterator:

model = {
  { player = "Cliff", age = 35, gender = "male" },
  { player = "Ally", age = 36, gender = "female" },
  { player = "Jasmine", age = 13, gender = "female" },
  { player = "Lauren", age = 6.5, gender = "female" }
}

function model:having(predicate)
    local index = 0 
    return function()
        while true do
            index = index + 1
            if index > #self then break end
            if predicate(self[index]) then return self[index] end
        end
    end
end

for item in model:having(function(m) return m.age < 30 end) do
    print(item.player)
end
断桥再见 2025-01-11 01:37:46

这是极其复杂和过度设计的。您想通过谓词过滤一个列表。那么就这样做吧;这是一个简单的循环。就写吧。

即使您绝对必须以函数式风格执行此操作(Lua 不是函数式语言。它可以以这种方式工作,但它不是函数式的),协程也不合适。

观察:

model = {
  { player = "Cliff", age = 35, gender = "male" },
  { player = "Ally", age = 36, gender = "female" },
  { player = "Jasmine", age = 13, gender = "female" },
  { player = "Lauren", age = 6.5, gender = "female" }
}

function for_each_array(list, operation)
  for key, value in ipairs(list) do
    operation(value)
  end
end

function filter_if(list, predicate)
  return function(value)
    if(predicate(value)) then
      list[#list + 1] = value
    end
  end
end

local list = {}
for_each_array(model, filter_if(list, function(each) return each.age < 30 end))

for_each_array(list, function(each) print(each.player) end)

看到了吗?根本不需要协程。

This is incredibly overcomplicated and overdesigned. You want to filter one list via a predicate. So do that; it's a simple loop. Just write it.

Even if you absolutely must do this in a functional style (Lua is not a functional language. It can work that way, but it's not functional), coroutines aren't appropriate.

Observe:

model = {
  { player = "Cliff", age = 35, gender = "male" },
  { player = "Ally", age = 36, gender = "female" },
  { player = "Jasmine", age = 13, gender = "female" },
  { player = "Lauren", age = 6.5, gender = "female" }
}

function for_each_array(list, operation)
  for key, value in ipairs(list) do
    operation(value)
  end
end

function filter_if(list, predicate)
  return function(value)
    if(predicate(value)) then
      list[#list + 1] = value
    end
  end
end

local list = {}
for_each_array(model, filter_if(list, function(each) return each.age < 30 end))

for_each_array(list, function(each) print(each.player) end)

See? No need for coroutines at all.

葬花如无物 2025-01-11 01:37:46

您可能想尝试模仿 Underscore.js JavaScript 库。

您的示例如下所示:

_ = require 'underscore'
model = {
  { player = "Cliff", age = 35, gender = "male" },
  { player = "Ally", age = 36, gender = "female" },
  { player = "Jasmine", age = 13, gender = "female" },
  { player = "Lauren", age = 6.5, gender = "female" }
}
result1 = _.select(model, function(p) return p.age < 30 end) -- traditional way
result2 = _(model):select(function(p) return p.age < 30 end) -- object-oriented style, calls can be chained
assert(_.is_equal(result1, result2))

请注意,Lua 不会为您提供任何其他语法糖(除了 : 运算符)。如果您确实想要更短的语法,您应该查看 Metalua,它允许您更改语言,并提供以下开箱即用的短函数语法:

result = _.select(model, |p| p.age < 30)

You may want to try Underscore.lua modeled after the Underscore.js JavaScript library.

Your example would look like this:

_ = require 'underscore'
model = {
  { player = "Cliff", age = 35, gender = "male" },
  { player = "Ally", age = 36, gender = "female" },
  { player = "Jasmine", age = 13, gender = "female" },
  { player = "Lauren", age = 6.5, gender = "female" }
}
result1 = _.select(model, function(p) return p.age < 30 end) -- traditional way
result2 = _(model):select(function(p) return p.age < 30 end) -- object-oriented style, calls can be chained
assert(_.is_equal(result1, result2))

Note that Lua won't give you any other syntax sugar (apart from the : operator). If you really want shorter syntax, you should look at Metalua, which allows you to change the language, and provides the following short function syntax out-of-the-box:

result = _.select(model, |p| p.age < 30)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文