如何“显示”不可显示的类型?
我正在使用data-reify并将graphvizeDSL 转换为一个很好的图形表示,用于内省。
作为一个简单的、人为的例子,请考虑:
{-# LANGUAGE GADTs #-}
data Expr a where
Constant :: a -> Expr a
Map :: (other -> a) -> Expr a -> Expr a
Apply :: Expr (other -> a) -> Expr a -> Expr a
instance Functor Expr where
fmap fun val = Map fun val
instance Applicative Expr where
fun_expr <*> data_expr = Apply fun_expr data_expr
pure val = Constant val
-- And then some functions to optimize an Expr AST, evaluate Exprs, etc.
为了使内省更好,我想打印存储在 DSL 数据类型的某些 AST 节点内的值。但是,通常任何a可能存储在 中Constant,即使那些没有实现Show. 这不一定是一个问题,因为我们可以限制Expr像这样的实例:
instance Show a => Show (Expr a) where
...
然而,这不是我想要的:我仍然希望能够打印,Expr即使a不是Show-able,通过打印一些占位符值(例如只是它的类型和它不可打印的消息)。
因此,如果我们有一个aimplementation Show,我们想要做一件事,如果一个特定的a没有,则另一件事。
此外,DSL 也有构造函数Map,Apply这甚至更成问题。构造函数在 中是存在的other,因此我们不能对other,a或 做任何假设(other -> a)。添加约束类型other的MapRESP。Apply构造函数会破坏Functorresp的实现。Applicative转发给他们。
但在这里我也想打印这些功能:
- 一个独特的参考。这始终是可能的(即使它是不漂亮,因为它需要
unsafePerformIO使用)System.Mem.StableName。 - 它的类型,如果可能的话(一个技术是使用
show (typeOf fun),但它要求fun是Typeable)。
我们再次遇到了一个问题,如果我们有一个f实施,我们想做一件事,如果没有Typeable,另一件事f。
这该怎么做?
额外免责声明:这里的目标不是为Show不支持它的类型创建“正确”的实例。没有愿望Read以后能够他们,或者print a != print b暗示a != b。
目标是以“适合人类内省”的方式打印任何数据结构。
我被困在的部分是,如果额外的约束对aresp持有,我想使用一种实现。(other -> a),但如果这些不存在,则为“默认”。也许FlexibleInstances这里需要类型类,或者类型族?我一直无法弄清楚(也许我一起走错了轨道)。