gpt4 book ai didi

ruby - 如何在 Ruby 中组织 Proc?

转载 作者:数据小太阳 更新时间:2023-10-29 08:02:20 25 4
gpt4 key购买 nike

将脚本从 OOP 转换为 FP,我试图了解如何将“方法包”(类)替换为“过程包”。 Procs 是那些可组合的 (<<),具有绑定(bind)的匿名微对象,但我还没有看到使用多个 #call 的示例。我的普通脚本有几十个方法:用 procs 替换它们需要某种容器来组织代码。

尝试将 Procs 存储到哈希中。但是 Hash 并不是为这个应用而设计的。例如,从同一哈希中的另一个过程调用一个过程是很尴尬的。

尝试将 Procs 存储到类中,与变量相关联。但是封装降低了我访问外部变量的能力(失去了闭包的一个关键优势)并使对过程的访问变得复杂(要么使用实例变量必须实例化类,要么使用类变量必须创建类访问器方法)。

试图将 Procs 存储到方法中,但这样做的好处在哪里。


require 'net/http'
require 'json'
require 'iron_cache'
require 'discordrb'

class Config
# config vars
end

data_space = {
:message => ""
}

bot = Discordrb::Bot.new(token: Config::DISCORD_TOKEN, ignore_bots: true)
channel = bot.channel(Config::DISCORD_CHANNEL_ID)
cache = IronCache::Client.new.cache("pa")

bot_control = {
:start => proc {bot.run(:async)},
:stop => proc do
bot.stop
exit(0)
end,
:send => proc {data_space[:message].then {|m| bot.send_message(channel, m)}},
"messaging?" => proc do |wish|
[ Config::MESSAGING[wish.first] , Config::NIGHTTIME_FLAG ].compact.first
end
}

cache_control = {
:get_flag => proc {|flag| cache.get(flag)&.value},
:set_wish => proc do |wish, exp_sec|
cache.put("messaging", wish.to_json, :expires_in => exp_sec)
data_space[:message] << "#{wish.first} got it!"
end,
:exp_sec => proc do
t = Time.now
(t-Time.new(t.year,t.month,t.day,Config::EXP_REF,0,0)).to_i
end,
:get_wish => proc do
msg = proc {cache_control[:get_flag].call("messaging")}
msg ? JSON.parse(msg) : [nil, nil]
end
}
bot_control[:start].call
data_space[:message] << "ah"
bot_control[:stop].call if (bot_control["messaging?"]<<cache_control[:get_wish]).call
(bot_control[:stop]<<bot_control[:send]).call

实际交付。

但这不是我认为可读的那种代码。或者是对 OOP 的改进。请指教。


编辑

看起来我尝试使用哈希对过程进行分组的尝试是正确的。如所述elsewhere Proc 中的散列将实例方法添加为#count、#keys 和#store 以访问和操作它。因此我可以这样写:


bc = proc { |args|
{
start: proc {...},
stop: proc {...}
}
}

bot_control = bc.call
bot_control[:start].call
bot_control[:stop].call

有一些注意事项。散列返回的值是过程和组合方法(<< 和 >>)被添加但它们不起作用。此外,我还没有找到如何从散列中引用其他值。虽然可以添加方法(默认为私有(private)但可以声明为公共(public))并从值中引用它们。

所以我获得了嵌套闭包(变量一直向下泄漏)但是此时的代码与常规类没有太大区别。 #new 变成了#call(Proc 毕竟是从 Method 继承的)但是在 FP 方向上没有太大的改进。请指教。

最佳答案

使用模块和常量。

module BotControl
Start = proc {bot.run(:async)}
Stop = proc do
bot.stop
exit(0)
end
Send = proc {DataSpace::Message.then {|m| bot.send_message(channel, m)}}
Messaging = proc do |wish|
[ Config::MESSAGING[wish.first] , Config::NIGHTTIME_FLAG ].compact.first
end
end

请注意,此代码不会按原样运行:bot 变量不可见!有几种方法可以解决这个问题,但它们超出了这个问题的范围(我的 2¢,它应该是这些函数的参数)。

用法看起来像

(BotControl::Messaging<<CacheControl::GetWish).call

您的函数应该是常量,这样可以保护您免于重新分配(哈希不会)。模块也不能被实例化/继承,所以这避免了任何类型的 OOPness。另一个好处是可以包含模块,因此如果您希望某些函数位于顶层,则可以轻松做到这一点。


编辑

您可能会想使用匿名模块来执行此操作,例如

BotControl = Module.new do
Start = proc {bot.run(:async)}
...
end

但这行不通,因为 Ruby 中常量的范围是词法,即在解析阶段而不是在运行时,它们在哪个模块中很重要。在上面的示例中,在解析器级别,Start 只是在顶层,因为它不在任何模块内(Module.new 只是一个方法调用,它在运行时评估)。所以这种方法实际上并没有将任何东西组合在一起。

关于ruby - 如何在 Ruby 中组织 Proc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57775590/

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