打印动态数据

时间:2018-02-23 15:57:07

标签: haskell generics types

我在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)添加新行....

随着更多原语和更大的元组的添加,这很快变得不切实际。

是否有一种算法方法可以为此动态数据生成字符串,特别是元组和列表。

2 个答案:

答案 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