Haskell Labeled AST: No instance for (Show1 (Label a)), 如何构造实例?

Haskell Labeled AST: No instance for (Show1 (Label a)), How to construct an instance?

我想要一个带注释的AST,所以我定义了那些递归数据结构 使用 Fix:

data Term a 
  = Abstraction Name a
  | Application a a
  | Variable Name
  deriving (Read,Show,Eq,Functor,Foldable,Traversable)

data Label a b 
  = Label a (Term b)
  deriving (Read,Show,Eq,Functor,Foldable,Traversable)

newtype Labeled a 
  = Labeled (Fix (Label a))
  deriving (Show)

我希望能够show一个Labeled a,但是编译器不高兴:

No instance for (Show1 (Label a))  
arising from the first field of `Labeled' (type `Fix (Label a)')

什么是 class Show1 以及如何定义能够显示 Labeled a 的适当实例?

Show1 is the class of what you might call "higher-order showables": type constructors which are showable whenever their argument is showable. For the purposes of fast-and-loose reasoning, you can think of Show1 as being declared roughly like this (see also showsPrec1):

class Show1 f where
    show1 :: Show a => f a -> String

这是另一种不准确但有用的思考方式Show1。我正在使用 the constraints library's "entailment" operator 来声明 f a 应该是 Show 的实例,只要 a 是。这个模型有点简单,但可能不太实用。

class Show1 f where
    show1 :: Show a :- Show (f a)

无论如何,Fix :: (* -> *) -> * 是可显示的,如果它的参数是高阶可显示的。来自 the source code:

instance Show1 f => Show (Fix f) where
  showsPrec d (Fix a) =
    showParen (d >= 11)
      $ showString "Fix "
      . showsPrec1 11 a

recursion-schemes 的作者本可以使用 StandaloneDeriving 来编写他们的 Show 实例...

deriving instance Show (f (Fix f)) => Show (Fix f)

...但此上下文需要 UndecidableInstances.

为给定仿函数编写 Show1 实例的最简单方法是使用 the deriving-compat library's Template Haskell helper.

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
{-# LANGUAGE TemplateHaskell #-}

import Text.Show.Deriving
import Data.Functor.Foldable


type Name = String
data Term a 
    = Abstraction Name a
    | Application a a
    | Variable Name
    deriving (Read, Show, Eq, Functor, Foldable, Traversable)

deriveShow1 ''Term

data Label a b = Label a (Term b)
    deriving (Read, Show, Eq, Functor, Foldable, Traversable)

deriveShow1 ''Label

newtype Labeled a = Labeled (Fix (Label a)) deriving (Show)

这将生成以下实例,

instance Show1 Term
instance Show a => Show1 (Label a)

为您提供 Labeled 派生实例的确切信息:

instance Show a => Show (Labeled a)

(PS。您是否考虑过使用像 bound 这样的库来管理您的术语语言中的名称和活页夹?)