2016-06-16 54 views
1

假設我們有一個快速檢查性質驗證的Functor滿足身份法的實例:是否可以將QuickCheck映射到類型列表?

-- | A covariant functor. 
class Map m where 
    (<@>) :: (a -> b) -> m a -> m b 

data Proxy a = Proxy 

-- | The functor identity law. 
prop_mapIdentityLaw :: (Eq (m a), Show (m a), Map m) 
        => Proxy (m a) 
        -> m a 
        -> Bool 
prop_mapIdentityLaw _ x = (id <@> x) == id x 

我想編寫運行對我創建實例此屬性的功能。東西大致類似於:

verify :: IO() 
verify = 
    mapM_ quickCheck [ prop_mapIdentityLaw t | t <- types ] 
    where 
    types = 
     [ Proxy :: Proxy (Id Int) ] 

如果我是另一個代理服務器添加到我的類型(例如Proxy :: Proxy (Option Int))名單,顯然是行不通的,因爲Proxy的類型是Proxy (Id Int)

幾年前我用了很多Haskell,但我不熟悉一些較新的擴展。我想知道是否有一種方法可以通過RankNTypesDataKinds或其他擴展組合來實現。

+1

這不是相關的,但我建議你用'==='而不是'=='替換'Bool'結果。通過這種方式,測試失敗將顯示平等測試的每一方面,而不僅僅是「假」。 – dfeuer

+0

感謝@dfeuer提示!我沒有意識到'==='操作符,並且早些時候一直在想是否有一種簡單的方法使它成爲'Property'。 –

回答

2

你需要在一個存在類型包裝相關的字典(實例的證人),這樣使「類型列表」齊:

-- Carries a Proxy with a bunch of dictionaries 
data ProxyA where 
    ProxyA :: (Eq (m a), Show (m a), Map m, Arbitrary (m a)) => Proxy (m a) -> ProxyA 

-- | The functor identity law. 
prop_mapIdentityLaw :: (Eq (m a), Show (m a), Map m) 
        => Proxy (m a) 
        -> m a 
        -> Bool 
prop_mapIdentityLaw _ x = (id <@> x) == id x 

verify :: IO() 
verify = forM_ types $ \ (ProxyA p) -> quickCheck $ prop_mapIdentityLaw p 
    where 
    types :: [ ProxyA ] 
    types = 
     [ ProxyA (Proxy :: Proxy (Id Int)) 
     , ProxyA (Proxy :: Proxy (Id Char)) 
     ] 

注意,因爲類型是如何生存的工作,你,由於該清單不是同質的,因此無法制作部分申請清單,如[ prop_mapIdentityLaw p | ProxyA p <- types ]。如果在頂部添加quickCheck,則它變得均勻。

相關問題