【问题标题】:Elixir: How to handle an "environment"Elixir:如何处理“环境”
【发布时间】:2014-08-01 01:53:57
【问题描述】:

我有一个相当大的函数“管道”来处理输入流。 在管道开始之前,会创建一个“环境”地图,该地图将提供额外的 管道中功能的信息。我现在在做什么,看起来 Elixir 要求的是将环境显式传递给每个函数。

对于每个函数在 管道(以及它们调用的许多函数)需要环境作为参数。 另一方面,我当然明白这可能只是“做它”的一部分 功能上”。

我的问题是:我是否遗漏了一些东西,也许是一个成语,来处理这个问题, 还是我应该习惯于传递看起来像“额外”的参数作为 函数式编程世界?

谢谢。

【问题讨论】:

    标签: elixir


    【解决方案1】:

    我建议为此使用代理。以下是完全组成的,但向您展示了不同的操作,并且类似于您可能想要的处理方式:

    def process(data) do
      {:ok, agent} = Agent.start_link(fn -> %{data: data, count: 0} end)
      process(data, agent)
    end
    
    def process(agent) when is_pid(agent) and bar > 0 do
      transformed = do_stuff_with(data)
      Agent.get_and_update(agent, fn %{count: count} = state ->
        updated = %{state | :data => transformed, :count => count + 1}
        {updated, updated}
      end
      process(agent)
    end
    
    def process(agent) when is_pid(agent) and bar == 0 do
      Agent.cast(agent, fn %{count: count} = state ->
        %{state | :count => count + 1}
      end
      process(agent)
    end
    
    def process(agent) when is_pid(agent) do
      Agent.get(agent, fn state -> state.data end)
    end
    

    您无需传递状态,而是传递代理的 PID,并根据需要获取/更新代理的状态。

    【讨论】:

    • 好的,谢谢。这似乎是正确的,而且非常自然。
    • 这与传递地图本身有何不同?
    • 我更新了我的示例,因为我忘记删除传递原始数据。不过一般的想法是代理的存储临时状态,例如您在某些复杂处理期间可能拥有的状态。您可以显式传递所有这些状态,也可以使用代理来管理它。从根本上说,您实现了相同的目标,这在很大程度上取决于您选择哪条路径的上下文。也许并非所有处理阶段都需要当前状态,并且您不想传递未使用的东西。此解决方案只是状态显式传递的替代方案。
    • 我不认为仅仅为了避免传递参数而使用进程是一种正确的方法。当您需要容错和/或可伸缩性时,应该使用流程。诚然,最初的问题有些模糊,但我没有看到那里提到这些概念。使用进程实际上可能会带来额外的问题,例如性能下降(由于消息来回传递)和更复杂的日志(因为现在可能在两个不同的进程中发生错误)。因此,虽然进程绝对有用,但我不会说它们是通过各种函数传递状态的“最佳”解决方案。
    猜你喜欢
    • 1970-01-01
    • 2016-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 2019-07-24
    • 2019-04-18
    • 2023-03-22
    相关资源
    最近更新 更多