无法为此类型编写Show实例

Mat*_*hid 3 haskell typeclass

请考虑以下类型声明:

data Foobar x = Foo (x (Foobar x))
Run Code Online (Sandbox Code Playgroud)

现在Show为此编写一个实例.我赌你!

我随便写道deriving Show,期待GHC做到这一点.但它抱怨它无法做到.我想,"可怜的傻瓜",并开始自己定义.但是......嗯......哦,实际上那很有意思......显然Foobar x只有在x y可以展示的时候才能展示y......或......那样的东西...... aaargh!

现在我确定我不可能成为第一个定义这种类型的人.而且我不能成为第一个想要Show它的实例的人.所以有人必须弄清楚如何做到这一点.

Ant*_*sky 6

如果你只是指定明显的约束 - 并添加一些必要的语言编译指示 - 一切正常.为了显示Foobar,必须显示该字段Foo,因此我们需要Show (x (Foobar x))约束.如果我们要求这样做,一切都会成功:

{-# LANGUAGE FlexibleContexts, UndecidableInstances, StandaloneDeriving #-}

data Foobar x = Foo (x (Foobar x))
deriving instance Show (x (Foobar x)) => Show (Foobar x)
Run Code Online (Sandbox Code Playgroud)

然后:

?> print $ Foo [Foo [], Foo [Foo []]]
Foo [Foo [],Foo [Foo []]]
?> data SL a = S String | L [a] deriving Show
?> print $ Foo (L [Foo (S "a"), Foo (L [Foo (S "b"), Foo (L []), Foo (S "c")])])
Foo (L [Foo (S "a"),Foo (L [Foo (S "b"),Foo (L []),Foo (S "c")])])
Run Code Online (Sandbox Code Playgroud)

我对这项工作有点惊讶,但并不过分:-)


顺便说一句,这正是GHC问你,如果你尝试导出ShowFoobar:

?> data Foobar x = Foo (x (Foobar x)) deriving Show

<interactive>:2:45:
    No instance for (Show (x (Foobar x)))
      arising from the first field of ‘Foo’ (type ‘x (Foobar x)’)
    Possible fix:
      use a standalone 'deriving instance' declaration,
        so you can specify the instance context yourself
    When deriving the instance for (Show (Foobar x))
Run Code Online (Sandbox Code Playgroud)

我们所要做的就是使用StandaloneDeriving并准确指定该约束!


此外,要清楚,该StandaloneDeriving部分是可选的 - 它没有做任何魔术,并且实例不是很难手写:

instance Show (x (Foobar x)) => Show (Foobar x) where
  showsPrec p (Foo x) = showParen (p > app_prec) $
                          showString "Foo " . showsPrec (app_prec + 1) x
    where app_prec = 10 :: Int
Run Code Online (Sandbox Code Playgroud)

  • 这是[如何`Show`定义为'Fix`](https://hackage.haskell.org/package/recursion-schemes-4.1.2/docs/src/Data-Functor-Foldable.html#Fix)的递归-schemes. (2认同)

Dan*_*ner 6

以下是没有扩展的方法:

data Foobar x = Foo (x (Foobar x))

class Show1 f where
    showsPrec1 :: Show a => Int -> f a -> ShowS

instance Show1 f => Show (Foobar f) where
    showsPrec n (Foo v) = ("Foo " ++) . showsPrec1 n v -- doesn't handle n correctly because that's not the point of the question and would only distract from the actual important idea
Run Code Online (Sandbox Code Playgroud)

Show1类(和标准类型某些情况下),也可在Hackage.定义它的模块使用了一些扩展 - 但只是为了减少样板,而不是启用任何无聊的旧Haskell2010无法做到的事情.