我在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)添加新行....
随着更多原语和更大的元组的添加,这很快变得不切实际。
是否有一种算法方法可以为此动态数据生成字符串,特别是元组和列表。
答案 0 :(得分:2)
我只能设法获得这个可怕的解决方案。
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeApplications #-}
{-# OPTIONS -Wall #-}
import Type.Reflection
import Data.Dynamic
我们在此定义TyCon
和(,)
的{{1}}。 (我很确定必须有一种更简单的方法。)
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
,但我现在看不出怎么做。
赎回部分是方法非常通用,可以很容易地适应其他类型的构造函数。
答案 1 :(得分:2)
我喜欢另一个答案的主要思想,但它似乎以相当迂回的方式得到它的位置。以下是我如何设计相同的想法:
Information:Gradle tasks [:app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:mockableAndroidJar, :libraries:Jumble:generateDebugSources, :libraries:Jumble:generateDebugAndroidTestSources, :libraries:Jumble:mockableAndroidJar]
Error:Could not determine the dependencies of task ':app:preDebugBuild'.
> Could not resolve all task dependencies for configuration ':app:debugRuntimeClasspath'.
> Could not resolve project :libraries:Jumble.
Required by:
project :app
> Cannot choose between the following configurations of project :libraries:Jumble:
- debugRuntimeElements
- releaseRuntimeElements
All of them match the consumer attributes:
- Configuration 'debugRuntimeElements':
- Required com.android.build.api.attributes.BuildTypeAttr 'debug' but no value provided.
- Found com.android.build.api.attributes.BuildTypeAttr 'debug' but wasn't required.
- Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' but no value provided.
- Found com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' but wasn't required.
- Found com.android.build.gradle.internal.dependency.VariantAttr 'debug' but wasn't required.
- Required org.gradle.api.attributes.Usage 'java-runtime' and found compatible value 'java-runtime'.
- Configuration 'releaseRuntimeElements':
- Required com.android.build.api.attributes.BuildTypeAttr 'debug' but no value provided.
- Found com.android.build.api.attributes.BuildTypeAttr 'release' but wasn't required.
- Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' but no value provided.
- Found com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' but wasn't required.
- Found com.android.build.gradle.internal.dependency.VariantAttr 'release' but wasn't required.
- Required org.gradle.api.attributes.Usage 'java-runtime' and found compatible value 'java-runtime'.
第一次模式匹配是相当满口的,但在玩了几种不同的格式化方式后,我确信没有办法让它看起来不错。你可以在ghci中试试:
{-# 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