乙烯基:具有需要所有字段共享约束的函数的rtraverse

时间:2015-04-05 14:03:38

标签: haskell vinyl

我构建了一个Vinyl记录的简单示例。首先,一些语言编译指示和导入:

{-# 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将成为解决方案的一部分,但我不知道如何使用它。

1 个答案:

答案 0 :(得分:6)

你是正确的,reifyConstraint将解决这个问题。此函数的作用是将(或#34; reify")约束转换为数据类型,即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 x@(Compose (Dict a)) = print a >> return x

请注意,Show上不需要a约束 - Show类字典存储在Dict数据类型中。你可以使用这个功能。

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