在 Haskell 和 "show" 中出现歧义

Ambiguous occurrence in Haskell with "show"

我是函数式编程的新手,我正在尝试使用 Haskell 创建和显示堆栈。我希望我的程序能够向我展示我正在使用它构建的 Stack。这是我的代码:

module Stack (Stack, empty, push, pop, top, isEmpty) where
    data Stack a       = EmptyStack | Stk a (Stack a)
    push x s           = Stk x s
    top (Stk x s)      = x
    pop (Stk _ s)      = s
    empty              = EmptyStack
    isEmpty EmptyStack = True
    isEmpty (Stk x s)  = False`

    instance Show a => Show (Stack a) where
    show EmptyStack = "|"
    show (Stk a b) = (show a) ++ " <- " ++ (show b)

对于 "show (push 1 empty)",我希望得到这样的答案(或多或少):“ 1 <- | ” 但是我无法编译代码。当我尝试时,它显示以下错误:

[1 of 1] Compiling Stack            ( Stack.hs, interpreted )

Stack.hs:12:27:
    Ambiguous occurrence ‘show’
    It could refer to either ‘Stack.show’, defined at Stack.hs:11:9
                      or ‘Prelude.show’,
                         imported from ‘Prelude’ at Stack.hs:1:8-12
                         (and originally defined in ‘GHC.Show’)

Stack.hs:12:47:
    Ambiguous occurrence ‘show’
    It could refer to either ‘Stack.show’, defined at Stack.hs:11:9
                      or ‘Prelude.show’,
                         imported from ‘Prelude’ at Stack.hs:1:8-12
                         (and originally defined in ‘GHC.Show’)
Failed, modules loaded: none.

我理解程序可能会将 Prelude 中的 "show" 与 be 定义的 "show" 混淆的错误,但我在我的代码中看不到该错误。另外,有小伙伴代码相同,程序运行良好

有什么我必须改变或者我错过了什么?

谢谢!

所以第一个问题是您在为我们粘贴的代码中有一个 ` 字符。您的第二个问题是您不需要缩进模块中的所有行;我看到的大多数 Haskell 模块 不会 缩进模块的主体。您的第三个问题是您不需要 show ashow b 周围的括号:Haskell 中的优先级非常简单;括号始终具有最高优先级,其次是函数应用程序(left-associative 或 "greedy nom",函数总是吞噬它在其前面看到的第一件事),然后是定义优先级的运算符,然后是特殊句法形式,如 \a ->letdowhere。这些通常是审美问题,但您可能仍然关心。

你的最后一个问题在这里:

instance Show a => Show (Stack a) where
show EmptyStack = "|"
show (Stk a b) = (show a) ++ " <- " ++ (show b)

您希望 Haskell 将其转换为单个语句:

instance Show a => Show (Stack a) where show tmpvar = case tmpvar of { EmptyStack -> "|"; Stk a b -> show a ++ " <- " ++ show b }

但是 Haskell 将其变成了两行:

instance Show a => Show (Stack a) where {} 

show tmpvar = case tmpvar of { EmptyStack -> "|"; Stk a b -> show a ++ " <- " ++ show b }

所以 multiple-definition 被正确转换为 case-dispatch,但它没有放在上面的花括号内!因此,您可以通过使用空格缩进行来省略花括号 {}。在 where 之后,Haskell 没有看到任何明确的 {} 所以它开始寻找缩进行,它看到了 0 个,所以它将子句转换为 where {} (感谢@chi)。

没有在大括号中,无论是否因为缩进,新行定义了一个不同的函数,Stack.show,不同于属于 Show 的导入的 Prelude.show类型类。问题在于它还引用了一个名为 show 的函数,该函数现在是模棱两可的:这是一个 递归 调用具有无限类型 show :: Stack (Stack (Stack ...)) -> String 的函数还是 调度 调用有限类型的函数show :: (Show a) => Stack a -> String?在它试图找出这些类型之前,它会说 "stop it, I don't know what you mean, please clarify."

可能您的意图是:

instance Show a => Show (Stack a) where
    show EmptyStack = "|"
    show (Stk a b) = show a ++ " <- " ++ show b

此缩进提示 Haskell 编译器将以下两个语句接受到 where 子句中。