Haskell 显示错误?

The*_*ave 0 haskell types show

所以在一个文件中我有

import Data.String
import MyShow

data Tree a b = Leaf a | Branch b (Tree a b) (Tree a b)

instance (Show a, Show b) => Show (Tree a b) where
   show (Branch n t1 t2) = "(" ++ myshow t1 ++ myshow n ++ myshow t2 ++ ")"
   show (Leaf l) = myshow l

newtype MyString = MyString String

instance Show MyString where
    show (MyString s) = s
Run Code Online (Sandbox Code Playgroud)

在另一个名为 MyShow.hs 的文件中我有

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module MyShow where

class MyShow a where
    myshow :: a -> String

instance {-# OVERLAPPING #-} MyShow String where
    myshow s = s
    
instance Show a => MyShow a where
    myshow = show
Run Code Online (Sandbox Code Playgroud)

当我在 ghci 中加载第一个文件时,(Branch "+" (Leaf 1) (Leaf 2)显示(1"+"2),当我尝试时"(" ++ myshow (Leaf 1) ++ myshow "+" ++ myshow (Leaf 2) ++ ")",显示(1+2),这就是我想要的。

造成这种差异的原因是什么?如何解决?

che*_*ner 5

您的定义Show (Tree a b)仅需要a并且bShow实例,而不是MyShow实例。因此(我认为我无法准确解释原因), 的实例Show a => MyShow a优先于MyShow String,因为类型检查器不知道是否有可能a拥有实例。MyShow

如果将约束更改为

instance (MyShow a, MyShow b) => Show (Tree a b) where
Run Code Online (Sandbox Code Playgroud)

然后show (Branch "+" (Leaf 1) (Leaf 2))将按预期工作:myshow "+"将使用MyShow String实例,而不是Show a => MyShow a实例。

  • 顺便说一句,这种问题是应尽可能避免重叠实例的原因之一。 (4认同)
  • 为了准确解释原因,请将实例视为一种类型级函数,将约束作为参数,将实例本身作为结果。由于这个“函数”不将 `MyShow` 实例作为参数,因此它无法访问它们。但它不会出错,因为幸运的是,有一个通用的“MyShow”实例,它可以从它所拥有的“Show”实例中构造出来。 (3认同)