2016-09-28 58 views
2

比方說,我有提升的數據類型:消除圖案GADT匹配時構造靜態已知

data GADTConstructor = IntConstructor | StringConstructor 

然後,我創建GADT:

data MyGADT (a :: GADTConstructor) where 
    MyInt :: Int -> MyGADT IntConstructor 
    MyString :: String -> MyGADT StringConstructor 

和模式匹配功能:

printMyMyGADT :: MyGADT a -> IO() 
printMyMyGADT (MyInt i) = printInteger i 
printMyMyGADT (MyString s) = printString s 

這裏實際的GADT的構造函數由編譯時已知的GADT類型索引唯一確定。是否有可能強制GHC在運行時忽略任何模式匹配,並假設實際分支靜態已知,生成代碼?

+0

我相當肯定GHC在沒有幫助的情況下無法做到這一點(例如'RULES' pragmas)。無論如何,只要你有像打印這樣昂貴的'IO'操作,GADT構造函數的匹配開銷就無關緊要。 – leftaroundabout

+0

感謝您的建議。這不是用於打印整數,真正的代碼以嚴格的循環讀取內存和模式匹配,與沒有模式匹配的基線代碼相比,開銷高達60%。我會嘗試用'RULES'優化它。 – schernichkin

+1

請注意,這種優化也必須與嚴格性分析交互。考慮'printMyMyGADT(undefined :: MyGADT IntConstructor)'。 – Toxaris

回答

3

那麼當GHC編譯printMyMyGADT類型索引a不知道過程(這是一個變量)和信息的有關a不可在運行時要麼,所以printMyMyGADT必須做在其上構造它所傳遞的一個分支。

如果不是

printMyMyGADT' :: MyGADT IntConstructor -> IO() 
printMyMyGADT' (MyInt i) = printInteger i 

然後GHC是能夠傳播,只有MyInt構造,可以將生成的代碼信息,避免在構造一個分支。

如果你打電話給在其類型變量a被稱爲是IntConstructor如果是內聯然後GHC將簡化內聯表達類似printMyMyGADT',再分支將避免上下文原printMyMyGADT。這可能也適用於專業化,我不確定。

所有這些在實踐中都有些不相關,因爲在所有情況下printMyMyGADT需要處理傳遞未評估表達式的情況。對我們看到的兩個構造函數中的哪一個進行分支的代價不過是檢查我們是否首先傳遞了構造函數的代價。

+0

我不認爲*專業化將有助於沒有一門課。它可能會使用'MyPrint類myPrint :: myGADT a - > IO()',有效地將這兩種情況通過統一的API分成兩個函數。 – dfeuer