Elixir 中表达式的惰性评估

Lazy evaluation of expression in Elixir

我想弄清楚在 clojure 中是否有一个类似于 delay 的宏来获得一个可以稍后计算的惰性表达式/变量。

用例是 Map.get/3 的默认值,因为默认值来自数据库调用,所以我更希望只在需要时调用它。

执行此操作的一种方法是使用进程。例如,地图可以包装在像 GenServer 或 Agent 这样的进程中,其中默认值将被延迟计算。

默认值可以是进行昂贵调用的函数。如果 Map.get/3 未被用于 return 函数,您可以检查该值是否是一个函数,如果它是 returned 则调用它。像这样:

def default_value()
  expensive_db_call()
end

def get_something(dict, key) do
  case Map.get(dict, key, default_value) do
    value when is_fun(value) ->
      value.() # invoke the default function and return the result of the call
    value ->
      value # key must have existed, return value
  end
end

当然,如果地图包含函数,则此类解决方案可能行不通。

同时检查 Elixir 的 Stream 模块。虽然我不知道它是否有助于解决您的特定问题,但它确实允许进行惰性评估。来自文档:

Streams are composable, lazy enumerables. Any enumerable that generates items one by one during enumeration is called a stream. For example, Elixir’s Range is a stream:

the Stream documentation 中提供了更多信息。

Elixir 的宏可用于编写用于条件评估的简单包装函数。我在下面列出了一个要点,尽管它可能是 better/smarter 方式。

https://gist.github.com/parroty/98a68f2e8a735434bd60

"Generic" 懒惰有点难解决,因为这是一个相当宽泛的问题。流允许可枚举的惰性,但我不确定表达式的惰性意味着什么。例如 x = 1 + 2 的惰性形式是什么?什么时候评估?

想到表达式的惰性形式是过程表达式:

def x, do: 1 + 2

因为 x 的值在实际调用表达式之前不会被计算(据我所知)。如果我在这一点上错了,我相信其他人会纠正我。但我认为这不是你想要的。

也许您想重新表述您的问题——省略流和枚举值的惰性求值。

Map.get_lazyKeyword.get_lazy 在需要时推迟生成默认值,链接下面的文档

https://hexdocs.pm/elixir/Map.html#get_lazy/3

https://hexdocs.pm/elixir/Keyword.html#get_lazy/3

你可以将它包裹在一个匿名函数中,然后在调用该函数时对其进行计算:

iex()> lazy = fn -> :os.list_env_vars() end
#Function<45.79398840/0 in :erl_eval.expr/5>
iex()> lazy.()