我在haskell中有一个系统,它使用Data.Dynamic和Type.Reflection来执行推理和计算。我希望能够打印结果。
当提供类型时,打印是容易的。
foo :: Dynamic -> String
foo dyn = case tyConName . someTypeRepTyCon . dynTypeRep $ dyn of
"Int" -> show $ fromDyn dyn (0 :: Int)
"Bool" -> show $ fromDyn dyn True
_ -> "no chance"但是如果我想要打印元组,我必须为每一行添加一个新行,例如(Int,Bool),(Bool,Int),(Char,Int,Banana)。
随着添加更多的原语和更大的元组,这很快就变得不切实际了。
有一种算法方法可以为这个动态数据生成字符串,特别是为元组和列表。
发布于 2018-02-24 02:44:50
我喜欢另一个答案的主要观点,但它似乎得到了一个相当迂回的方向。下面是我所提出的同样的想法:
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
import Type.Reflection
import Data.Dynamic
showDyn :: Dynamic -> String
showDyn (Dynamic (App (App (eqTypeRep (typeRep @(,)) -> Just HRefl) ta) tb) (va, vb))
= concat [ "DynamicPair("
, showDyn (Dynamic ta va)
, ","
, showDyn (Dynamic tb vb)
, ")"
]
showDyn (Dynamic (eqTypeRep (typeRep @Integer) -> Just HRefl) n) = show n
showDyn (Dynamic tr _) = show tr第一个模式匹配是相当不错的,但在玩了几种不同的方式格式化它,我相信,只是没有办法使它看起来很好。你可以在ghci试试:
> showDyn (toDyn ((3,4), (True, "hi")))
"DynamicPair(DynamicPair(3,4),DynamicPair(Bool,[Char]))"发布于 2018-02-23 17:39:49
我只能设法得到这个可怕的解决方案。
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeApplications #-}
{-# OPTIONS -Wall #-}
import Type.Reflection
import Data.Dynamic在这里,我们定义了用于(,)和Int的Int。(我很确定一定有更简单的方法。)
pairTyCon :: TyCon
pairTyCon = someTypeRepTyCon (someTypeRep [('a','b')])
intTyCon :: TyCon
intTyCon = someTypeRepTyCon (someTypeRep [42 :: Int])然后对Dynamic型进行解剖。首先,我们检查它是否是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上面的内容很难看,因为我们首先使用TyCon来匹配模式,而不是使用模式匹配,这就阻止了将v类型细化为Int。因此,我们仍然必须求助于eqTypeRep来执行我们已经知道必须成功的第二次检查。
例如,我认为通过预先检查eqTypeRep可以使它变得很漂亮。或fromDyn.这不重要。
重要的是,下面的两个箱子更凌乱,不能以同样的方式使之美观,据我所见。
-- 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"上面我们匹配TypeRep,以便它代表某种类型的p a1 a2。我们要求p的表示形式为pairTyCon。
和以前一样,这不会触发类型细化,因为它是用==而不是模式匹配完成的。我们需要执行另一个显式匹配来强制p ~ (,),另一个用于最终细化v :: (a1,a2)。叹一口气。
最后,我们可以使用fst v和snd v,再次将它们转换为Dynamic,并对它们进行配对。实际上,我们将原始的x :: Dynamic转换为类似于(fst x, snd x)的东西,其中两个组件都是Dynamic。现在我们可以恢复了。
我真的很想避开error,但我现在不知道该怎么做。
弥补部分是该方法是非常通用的,可以很容易地适应其他类型的构造函数。
https://stackoverflow.com/questions/48951745
复制相似问题