2012-04-28 56 views
5

我很好奇在Functional Pearl: Implicit Configurations文章Kiselyov和撣討論了反對implicit parameters隱式參數是GHC內聯的難點嗎?

在存在隱式參數的情況下內聯代碼(β-reduce)並不健全。

真的嗎?我希望GHC應該與傳遞的隱式參數一樣嵌入到相同的範圍內,否?

我相信我理解他們的反對意見認爲:

一個術語的行爲可以改變,如果它的簽名是添加,刪除或更改。

GHC的用戶文檔解釋說,編程人員必須注意圍繞polymorphic recursionmonomorphism restriction。這在某種程度上是內聯問題的意思嗎?

我想這多態遞歸的例子講述了他們的「概括了隱含參數」,以及是什麼意思?還要別的嗎?

ReifiesStorable類型的Data.Reflection類真的是一個明智的解決這些困難的方法嗎?它每次訪問時似乎都會對整個隱式數據結構進行反序列化,這對性能而言聽起來是災難性的。例如,我們可能希望我們的隱含信息是Cayley表或字符表,它佔據了一列ram,並且必須在數百萬代數操作中訪問。

有可能還有一些更好的解決方案,它採用隱含參數,或另一種技術的編譯器可以輕鬆地優化,在幕後,而仍然使用狀態的線程或任何保證通過類型系統嗎?

回答

7

是,從GHC手冊中的例子顯示瞭如何將一個類型簽名可以改變與隱含參數代碼的語義,並且我相信這是他們的意思,打破內聯;內嵌len_acc1的應用程序與len_acc2的應用程序產生相同的代碼,儘管兩者具有不同的語義。

至於要概括隱含參數,這意味着你可以不寫,可以在多個隱參數操作功能;沒有任何機制可以對它們進行抽象,因爲函數使用的隱式參數是由它的類型決定的。通過反射,您可以輕鬆編寫像doSomethingWith :: (Reifies s a, Num a) => Proxy s -> a這樣的函數,它可以在任何可以表示數值的類型上運行。

至於ReifiesStorable,你看的是舊版本的反射包; latest version有一個非常有效的實現,其中reify的成本只有函數調用的成本。 請注意,即使使用舊的實現,您通常不會直接使用ReifiesStorable類,而是使用ReifiesStorable來代替StablePtr,因此只有幾個字節最終被複制,而不是整個對象。 (這也是本文最初的實現。)這兩種實現方式對於實際應用來說肯定足夠快,而舊的「慢速」實現花費大約100 ms來確定和反映100000個值,而新實現在10以下女士。

(全面披露:我在新的實施工作。)

快速實現取決於Haskell的實現細節。較早的較慢的實現自動用於Haskell實現,該實現尚未經過快速實現;到目前爲止,GHC和擁抱已被證明可以快速實施。您可以通過-fslow請求緩慢執行,但除非GHC顯着檢查其類型類的實現,否則它不可能停止工作。 (即使是這樣,你只需要重新編譯使用反射的軟件包就可以再次使用它。)

+0

Ahh很好,所以'Data.Reflection'現在都是黑魔法。 :)有沒有你推薦閱讀的任何代碼或文章? 'Data.Reflection'已經讓我更加清楚,現在我注意到了examples目錄。不過,我應該在'Data.Tagged'和'Data.Proxy'上閱讀另一件事。 – 2012-04-28 14:24:30