2017-08-17 64 views
3

我玩弄單身的專業化:專業單參數

{-# LANGUAGE DataKinds  #-} 
{-# LANGUAGE GADTs   #-} 
{-# LANGUAGE KindSignatures #-} 

module Data.Test where 

data SingBool (b :: Bool) where 
    STrue :: SingBool 'True 
    SFalse :: SingBool 'False 

sing :: SingBool b -> Bool 
sing SFalse = False 
sing STrue = True 
{-# SPECIALIZE sing :: SingBool 'False -> Bool #-} 

這個專門爲類似如下:

singSFalse :: SingBool 'False -> Bool 
singSFalse SFalse = False 

我希望它產生的singSFalse _ = False的RHS代替。

這種強制解壓只是爲了滿足類型檢查器,還是在模式匹配中涉及實際的運行時開銷?我想GHC不會放棄參數的模式匹配來解釋bottom,以免增加懶惰。但是我希望在我開始通過Proxy + a SingI-樣式類型開始建模之前,我很確定。

+1

我認爲你的診斷是正確的,但我應該提到,最後我聽說GHC文檔是關於'SPECIALIZE'和GADT的謊言。該編譯指示(可能)不起作用,並且如果通過構造函數專門化發生特化。 – dfeuer

+0

嗯,這解釋了警告(沿着'SPECIALIZE在這裏沒有效果')。但即使在我的更大的用例中,GHC也可以在沒有警告的情況下正確地專注於模塊邊界,這可能是因爲還有一些類型的類字典,我並沒有真正專注於這些字典。 編輯:這可能要反正做可以內聯...... –

+0

,我與該類型級解決方案https://github.com/sgraf812/pomaps/blob/ebfad35ca1864c6cb8f5921fb804cac26ca944f7/library/Data/POMap/Internal去。hs#L207-L211 –

回答

2

好的,主要回答我自己的問題:知道SingBool 'False只有一個居民是不足以讓GHC擺脫模式匹配的,因爲我們可以稱之爲singSFalse (error "matched"),例如singSFalse (error "matched")。底部永遠是另一個居民。因此,專門化(例如基於具體的內聯TypeApplication s的內聯)在Haskell(惰性,非全部)w.r.t中並不能很好地處理singletons(將這些類型的應用程序轉化爲可能是常量值的應用程序)。零成本抽象。

然而,通過使用SingI風格類型的類與代理(如singByProxy),我們沒有同樣的問題:

{-# LANGUAGE DataKinds  #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE MagicHash  #-} 

module Data.Test where 

import   GHC.Exts (Proxy#) 

class SingIBool (b :: Bool) where 
    sing :: Proxy# b -> Bool 

instance SingIBool 'False where 
    sing _ = False 

instance SingIBool 'True where 
    sing _ = True 

refurbulate :: SingIBool b => Proxy# b -> Int 
refurbulate p 
    | sing p = 0 
    | otherwise = 1 

專業化refurbulate @(Proxy# 'False)不僅將實現爲const False,也在值級別上不會有任何Proxy#參數通過,所以它不是coerce False :: Proxy# -> Bool。整齊!但是,我沒有得到使用單身在現實世界中:(


回顧一下爲什麼單身失敗(得到優化)和類型類工作:

通過專門類型的類的實例,我們結識sing的RHS,從中我們可以推斷總體。

通過專業的單,我們結識了參數的計算結果爲,什麼價值,如果評估終止

知道類型類方法x ::()的規範RHS比僅僅知道參數x ::()只能計算非整數,懶惰(例如,非整數)值中的一個值更具信息性。哈斯克爾)的設置。

+0

模式匹配不應該非常昂貴。這真的只是'seq';一旦價值在WHNF,就沒有別的事可做了。如果您使用產生「SingBool」的'SingI'類方法,我相信''sing''應用應該被正確優化。過分基於類的方法存在的問題是當類型不是靜態的時候會變得混亂。 – dfeuer

+0

當代碼的其餘部分穩定時,我可能會對此進行基準測試。 –