5

我想要一个带注释的 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)

我希望能够showa Labeled a,但编译器不高兴:

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

什么是类Show1,如何定义适当的实例才能显示Labeled a

4

1 回答 1

3

Show1是你可能称之为“高阶可显示对象”的类:类型构造函数,只要它们的参数是可显示的,就可以显示。出于快速和宽松推理的目的,您可以将其Show1视为大致如下声明(另请参见 参考资料showsPrec1):

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

这是另一种不准确但有用的思考方式Show1。我正在使用libraryconstraintsentailment”运算符来声明它f a应该是Showwhen ais 的一个实例。这个模型有点简单,但可能不太实用。

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

无论如何,Fix :: (* -> *) -> *如果它的论点是一个高阶可显示的,它就是可显示的。从源代码

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为给定函子编写实例的最简单方法是使用deriving-compatTemplate Haskell 助手

{-# 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来管理你的术语语言中的名称和活页夹?)

于 2017-09-08T15:20:12.797 回答