首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >打印动态数据

打印动态数据
EN

Stack Overflow用户
提问于 2018-02-23 15:57:06
回答 2查看 158关注 0票数 2

我在haskell中有一个系统,它使用Data.Dynamic和Type.Reflection来执行推理和计算。我希望能够打印结果。

当提供类型时,打印是容易的。

代码语言:javascript
复制
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)。

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

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-24 02:44:50

我喜欢另一个答案的主要观点,但它似乎得到了一个相当迂回的方向。下面是我所提出的同样的想法:

代码语言:javascript
复制
{-# 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试试:

代码语言:javascript
复制
> showDyn (toDyn ((3,4), (True, "hi")))
"DynamicPair(DynamicPair(3,4),DynamicPair(Bool,[Char]))"
票数 2
EN

Stack Overflow用户

发布于 2018-02-23 17:39:49

我只能设法得到这个可怕的解决方案。

代码语言:javascript
复制
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeApplications #-}
{-# OPTIONS -Wall #-}

import Type.Reflection
import Data.Dynamic

在这里,我们定义了用于(,)IntInt。(我很确定一定有更简单的方法。)

代码语言:javascript
复制
pairTyCon :: TyCon
pairTyCon = someTypeRepTyCon (someTypeRep [('a','b')])

intTyCon :: TyCon
intTyCon = someTypeRepTyCon (someTypeRep [42 :: Int])

然后对Dynamic型进行解剖。首先,我们检查它是否是Int

代码语言:javascript
复制
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.这不重要。

重要的是,下面的两个箱子更凌乱,不能以同样的方式使之美观,据我所见。

代码语言:javascript
复制
   -- 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 vsnd v,再次将它们转换为Dynamic,并对它们进行配对。实际上,我们将原始的x :: Dynamic转换为类似于(fst x, snd x)的东西,其中两个组件都是Dynamic。现在我们可以恢复了。

我真的很想避开error,但我现在不知道该怎么做。

弥补部分是该方法是非常通用的,可以很容易地适应其他类型的构造函数。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48951745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档