2015-02-24 106 views
3

我试图弄清楚clojure中是否有类似于delay的宏以获得可以稍后评估的懒惰表达式/变量。Elixir中表达式的懒惰评估

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

+0

查看源在Clojure的(这里:https://github.com/clojure/clojure/blob/201a0dd9701e1a0ee3998431241388eb4a854ebf/src/jvm/clojure/lang/Delay.java)“延迟”它看起来像延迟接近到一个协议而不是一个宏。如果我是你,我会在Elixir中调查协议并以这种方式继续。 – 2015-02-25 14:49:48

+0

在问这个问题之前,我检查了'delay'源,有趣的是'delay'是在java中实现的,而不是clojure--它允许对表达式进行不同的构造和操作。 – NhanH 2015-02-25 23:14:40

回答

1

药剂的宏可用于编写简单的包装功能,有条件的评价。我已经在下面提出了一个要点,虽然它可能是更好/更聪明的方式。

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

+0

这也是我最终得到的解决方案,虽然我的代码使用if else,看起来好多了。 好像有没有更好的办法,除非我们实际上得到的编译器支持:-) 而一个缺点比较'delay'在Clojure是,我们必须写我们要利用一切功能的宏,而不是有一个通用运营商。 – NhanH 2015-02-25 01:02:22

0

执行此操作的一种方法是使用进程。例如,地图可以封装在GenServer或代理(http://elixir-lang.org/docs/v1.0/elixir/Agent.html)等进程中,其中默认值将被评估为懒惰。

+0

我不太关注你如何使用懒惰评估的过程,你介意把一些代码作为例子吗? – NhanH 2015-02-25 01:06:12

1

默认值可以是一个功能,它使昂贵的通话。如果Map.get/3未用于返回函数,则可以检查该值是否为函数,并在返回时调用它。像这样:

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模块。虽然我不知道它会帮助解决您的特定问题,但确实可以进行懒惰评估。从文档:

流是可组合的,惰性枚举。任何在枚举过程中逐一生成项目的枚举被称为流。例如,药剂的范围是流:

更多信息可在文档中:http://elixir-lang.org/docs/master/elixir/Stream.html

+0

流不是我正在寻找的,我正在寻找一种方式来延迟任何表达。 您使用'case'的解决方案非常接近实际的解决方案,但解决方案需要使用宏来处理任意的表达式。 – NhanH 2015-02-25 01:05:43

0

“通用”懒惰是有点难啃的打击,因为这是一个相当宽泛的问题。流允许懒惰的枚举,但我不确定表达懒惰是什么意思。例如,x = 1 + 2的懒形式是什么?何时进行评估?

该想到用于表达式的懒惰形式的思想是一个过程表达:

def x, do: 1 + 2 

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

也许你想要改写你的问题 - 忽略流和对枚举值的惰性评估。