2015-04-05 60 views
3

我已經構造了一個Vinyl記錄的簡單示例。首先,一些語言編譯指示和進口:乙烯:rtraverse帶有需要所有字段共享的約束的函數

{-# LANGUAGE DataKinds, TypeOperators #-} 

import Data.Vinyl 
import Data.Vinyl.Functor 
import Control.Applicative 

實際例子(它採用爲了簡單起見,HList類型同義詞):

mytuple :: HList [Integer,Bool] 
mytuple = Identity 4 :& Identity True :& RNil 

這將編譯確定。但現在我想打印使用rtraverse黑膠唱片:

printi :: Show a => Identity a -> IO (Identity a) 
printi (Identity x) = print x *> pure (Identity x) 

main :: IO() 
main = rtraverse printi mytuple *> pure() 

這提供了以下錯誤:No instance for (Show x) arising from a use of ‘printi’。預計我猜想,因爲rtraverse預計沒有約束的函數。

如何解決這個問題?看起來reifyConstraint將成爲解決方案的一部分,但我不知道如何使用它。

回答

6

你是正確的,reifyConstraint將解決這個問題。這個函數所做的是將約束轉換(或「修正」)爲數據類型,即Dict數據類型。例如

>:t reifyConstraint (Proxy :: Proxy Show) mytuple 
(reifyConstraint (Proxy :: Proxy Show) mytuple) 
    :: Rec (Dict Show :. Identity) '[Integer, Bool] 

此記錄中的每個元素將具有表格Dict (Identity _)Dict被定義爲

data Dict c x where Dict :: c x => x -> Dict c x 

現在,你只需要一個穿越功能,它可以處理一個(Dict Show :. Identity) a作爲輸入。

printi :: Compose (Dict Show) Identity a -> IO (Compose (Dict Show) Identity a) 
printi [email protected](Compose (Dict a)) = print a >> return x 

請注意,您不需要在a一個Show約束 - 在Show類字典存儲在Dict數據類型。你可以使用這個功能。

main = rtraverse printi (reifyConstraint (Proxy :: Proxy Show) mytuple) 
+0

啊,我明白了。所以'Dict'是一個GADT,它上面的模式匹配可以讓你恢復匹配結果的'Show'約束? – danidiaz 2015-04-05 14:44:45

+0

就是如此。 – user2407038 2015-04-05 14:46:02