I have constructed a simple example of a Vinyl record. First, some language pragmas and imports:
{-# LANGUAGE DataKinds, TypeOperators #-}
import Data.Vinyl
import Data.Vinyl.Functor
import Control.Applicative
the actual example (it employs the HList type synonym for simplicity):
mytuple :: HList [Integer,Bool]
mytuple = Identity 4 :& Identity True :& RNil
This compiles ok. But now I want to print the Vinyl record using rtraverse:
printi :: Show a => Identity a -> IO (Identity a)
printi (Identity x) = print x *> pure (Identity x)
main :: IO ()
main = rtraverse printi mytuple *> pure ()
This gives the following error: No instance for (Show x) arising from a use of ‘printi’
. Which is expected I guess, because rtraverse
expects a function with no constraints.
How to solve this? It seems like reifyConstraint
will be a part of the solution, but I don't know how to use it.
You are correct that reifyConstraint will solve this problem. What this function does is convert (or "reify") constraints into datatypes, namely the Dict
datatype. For example
>:t reifyConstraint (Proxy :: Proxy Show) mytuple
(reifyConstraint (Proxy :: Proxy Show) mytuple)
:: Rec (Dict Show :. Identity) '[Integer, Bool]
Each element in this record will have form Dict (Identity _)
. Dict
is defined as
data Dict c x where Dict :: c x => x -> Dict c x
Now you simply need a traversal function which can handle a (Dict Show :. Identity) a
as an input.
printi :: Compose (Dict Show) Identity a -> IO (Compose (Dict Show) Identity a)
printi x@(Compose (Dict a)) = print a >> return x
Note that you don't need a Show
constraint on a
- the Show
class dictionary is stored in the Dict
datatype. You can rtraverse with this function.
main = rtraverse printi (reifyConstraint (Proxy :: Proxy Show) mytuple)