Haskell 元组可以有一个特殊的Show实例吗?

Haskell 元组可以有一个特殊的Show实例吗?,haskell,Haskell,我正在使用所谓的标记,这些标记是带有字符串和标记的元组,我希望能够以以下格式呈现在屏幕上:[tag:VALUE]我不能这样做,因为我做得不对。以下是设置: type Token value tag = ([value], tag) data Tag = Whitespace | Alpha | Digit | Punctuation | Terminal instance Show Tag where show Alpha = "A" show Whitespace = "W"

我正在使用所谓的标记,这些标记是带有字符串和标记的元组,我希望能够以以下格式呈现在屏幕上:
[tag:VALUE]
我不能这样做,因为我做得不对。以下是设置:

type Token value tag = ([value], tag)
data Tag = Whitespace | Alpha | Digit | Punctuation | Terminal
instance Show Tag where
    show Alpha = "A"
    show Whitespace = "W"
    show Digit = "D"
    show Punctuation = "P"
    show Terminal = "|"
type TextToken = Token Char Tag    
instance Show TextToken where
    show (values, tag) = "[" ++ show tag ++ ": " ++ values ++ "]"
在编译时崩溃:

Illegal instance declaration for `Show TextToken'
  (All instance types must be of the form (T t1 ... tn)
   where T is not a synonym.
   Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Show TextToken'
然后,我尝试用以下内容替换该实例:

instance Show ([Char], Tag) where
   show (values, tag) = "[" ++ show tag ++ ": " ++ values ++ "]"
又遇到了同样的问题:

Illegal instance declaration for `Show ([Char], Tag)'
  (All instance types must be of the form (T a1 ... an)
   where a1 ... an are *distinct type variables*,
   and each type variable appears at most once in the instance head.
   Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Show ([Char], Tag)'

有什么方法可以让它工作吗?

您需要使用新类型

newtype Tag a b = Tag (a, b)

instance (Show a, Show b) => Show (Tag a b) where
  show (Tag (a, b)) = "[" ++ show a ++ ": " ++ show b ++ "]"
您同时遇到了几个实例解析问题

  • 如果没有
    {-#语言类型同义词实例#-}
    pragma,则无法在实例定义中使用
    type
    同义词。。。即使他们非常清楚。启用它很好,它根本不是Haskell 98

  • 在实例定义中使用复杂的、嵌套的或多参数类型时,经常会与限制过度的Haskell 98实例定义发生冲突。在许多情况下,这很好,因此启用
    {-#LANGUAGE FlexibleInstances}
    pragma将允许这些OK机会

  • 最后,危险的是,
    ([Char],Tag)
    已经有了一个
    Show
    实例,多态的
    实例Show(a,b)
    带有
    a~[Char]
    b~ Tag
    。这意味着您将遇到
    OverlappingInstances
    警告

  • 您可以通过告诉GHC允许使用另一个pragma
    {-#LANGUAGE OverlappingInstances#-}
    来禁用此功能,但由于它可能会导致您自己和使用您的代码的其他人出现非常奇怪的运行时行为,因此非常不鼓励使用它

    通常,如果试图将实例声明“专门化”为特定类型,则需要不存在一般情况

    newtype Tup a b = Tup (a, b)
    
    instance Show (Tup Int Int) where
      show (Tup tup) = show tup
    
    instance Show (Tup String Int) where
      show (Tup (s, int)) = s ++ ": " ++ show int
    
    >>> show ("foo", 3)
    foo: 3
    >>> show (2, 3)
    (2, 3)
    >>> show ("foo", "bar")
    No instance for...
    

    您真正需要决定的事情是,您是否希望为不同种类的
    令牌使用不同的实例。如果需要,则使用
    newtype
    (或者一些人建议的编译器选项)。如果没有,则将
    Token
    a
    data
    ,并在generic
    Token
    类型上定义实例

    要制作
    newtype
    包装器,请执行以下操作:

    newtype TextToken = TextToken (Token Char Tag)
    
    然后为包装器声明
    Show
    实例:

    instance Show TextToken where
    
    对你来说,我还是建议你改变一下

    type Token value tag = ([value], tag)
    


    因为你有一个记录类型,所以你最好把它显式化。

    作为一个旁注,如果你还不熟悉的话,你可以看一看。经验丰富的Haskell程序员的建议是避免覆盖默认的
    Show
    实例
    show
    是调试的主要工具之一:您应该能够
    show
    a数据结构,然后将其复制并粘贴到
    ghci
    中进行进一步调试。您会注意到所有标准库都遵循此格式。如果您想要漂亮的打印,最好定义自己的函数。
    data Token value tag = Token [value] tag