Printing Dynamic Data

后端 未结 2 1745
青春惊慌失措
青春惊慌失措 2021-01-15 02:26

I have a system in haskell that uses Data.Dynamic and Type.Reflection to perform inference and calculations. I would like to be able to print the results.

Printing

2条回答
  •  抹茶落季
    2021-01-15 02:53

    I could only manage to obtain this horrible solution.

    {-# LANGUAGE GADTs, ScopedTypeVariables, TypeApplications #-}
    {-# OPTIONS -Wall #-}
    
    import Type.Reflection
    import Data.Dynamic
    

    Here we define the TyCon for (,) and Int. (I'm pretty sure there must be an easier way.)

    pairTyCon :: TyCon
    pairTyCon = someTypeRepTyCon (someTypeRep [('a','b')])
    
    intTyCon :: TyCon
    intTyCon = someTypeRepTyCon (someTypeRep [42 :: Int])
    

    Then we dissect the Dynamic type. First we check if it is an Int.

    showDynamic :: Dynamic -> String
    showDynamic x = case x of
       Dynamic tr@(Con k) v | k == intTyCon ->
          case eqTypeRep tr (typeRep @ Int) of
            Just HRefl -> show (v :: Int)
            _ -> error "It really should be an int"
       -- to be continued
    

    The above is ugly, since we first pattern match against the TyCon using == instead of pattern matching, which prevents the type refinement of v into an Int. So, we still have to resort to eqTypeRep to perform a second check which we already know has to succeed.

    I think it could be made pretty by checking eqTypeRep in advance, for instance. Or fromDyn. It does not matter.

    What matters is that the pair case below is even more messy, and can not be made pretty in the same way, as far as I can see.

       -- continuing from above
       Dynamic tr@(App (App t0@(Con k :: TypeRep p)
                (t1 :: TypeRep a1))
                (t2 :: TypeRep a2)) v | k == pairTyCon ->
          withTypeable t0 $
          withTypeable t1 $
          withTypeable t2 $
          case ( eqTypeRep tr (typeRep @(p a1 a2))
               , eqTypeRep (typeRep @p) (typeRep @(,))) of
            (Just HRefl, Just HRefl) ->
                "DynamicPair("
                ++ showDynamic (Dynamic t1 (fst v))
                ++ ", "
                ++ showDynamic (Dynamic t2 (snd v))
                ++ ")"
            _ -> error "It really should be a pair!"
       _ -> "Dynamic: not an int, not a pair"
    

    Above we match the TypeRep so that it represents something of type p a1 a2. We require that the representation of p to be pairTyCon.

    As before this does not trigger type refinement, since it is done with == instead of pattern matching. We need to perform another explicit match to force p ~ (,) and another for the final refinement v :: (a1,a2). Sigh.

    Finally, we can take fst v and snd v, turn them into Dynamic once again, and pair them. Effectively, we turned the original x :: Dynamic into something like (fst x, snd x) where both components are Dynamic. Now we can recurse.

    I would really like to avoid the errors, but I can not see how to do that at the moment.

    The redeeming part is that the approach is very general, and can be easily adapted to other type constructors.

提交回复
热议问题