2015-02-24 108 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的值將不被計算,直到表達被實際調用(據我知道)。我相信如果我在這一點上錯了,其他人會糾正我。但我不認爲這就是你想要的。

也許你想要改寫你的問題 - 忽略流和對枚舉值的惰性評估。