2

我正在使用所谓的标记,它们是带有字符串和标记的元组,我希望我能以以下格式在屏幕上呈现:[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)'

有没有办法让它工作?

4

2 回答 2

10

你会想要使用一个新类型

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 ++ "]"

您同时遇到了几个实例解析问题。

  1. 如果没有{-# LANGUAGE TypeSynonymInstances #-}编译指示,您就不能type在实例定义中使用同义词......即使它们非常清楚。启用它很好,它根本不是 Haskell 98。

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

  3. 最后,危险的是,已经有一个 的Show实例,即具有and([Char], Tag)的多态实例。这意味着您将违反警告。instance Show (a, b)a ~ [Char]b ~ TagOverlappingInstances

您可以通过告诉 GHC 允许OverlappingInstances使用另一个 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...
于 2013-11-05T20:00:47.703 回答
3

您真正需要决定的是,您是否需要针对不同类型的Token. 如果你这样做,那么使用一个newtype(或编译器选项,正如一些人建议的那样)。如果你不这样做,那么创建Token一个data并在泛型Token类型上定义你的实例。

要制作newtype包装器:

newtype TextToken = TextToken (Token Char Tag)

然后声明Show包装器的实例:

instance Show TextToken where

在你的情况下,我仍然建议改变

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

data Token value tag = Token [value] tag

因为无论如何你都有一个记录类型,所以你最好让它明确。

于 2013-11-05T20:06:18.067 回答