Reputation: 27766
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.
Upvotes: 2
Views: 153
Reputation: 14588
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)
Upvotes: 5