1

我是函数式编程的新手,我正在尝试用 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 中的“表演”与 be 定义的“表演”混淆的错误,但我在代码中看不到该错误。此外,有些伙伴的代码相同,程序运行良好。

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

谢谢!

4

1 回答 1

1

因此,第一个问题是您`为我们粘贴的代码中有一个字符。您的第二个问题是您不需要缩进模块中的所有行;我看到的大多数 Haskell 模块都不会缩进模块的主体。你的第三个问题是你不需要括号show ashow b:Haskell中的优先级非常简单;括号始终是最高优先级,其次是函数应用(左关联或“贪婪名义”,函数总是吞噬它前面看到的第一件事),然后是定义优先级的运算符,然后是特殊的句法形式像\a ->, let, do, where. 这些通常是美学问题,但您可能仍然关心。

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

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 }

所以多重定义被正确地转换为大小写调度,但它没有放在上面的花括号内!{}因此,您可以通过使用空格缩进行来省略花括号。之后where,Haskell 看不到任何显式{}的,所以它开始寻找缩进的行,它看到其中的 0 行,所以它将子句转换为where {}(感谢@chi)。

无论是否因为缩进,新行都没有在花括号中,它定义了一个不同的函数, ,与属于类型类Stack.show的导入不同。问题是它还引用了一个名为 的函数,现在它是模棱两可的:这是对具有无限类型的函数的递归调用还是对具有有限类型的函数的调度调用?在它试图弄清楚这些类型之前,它会说“停止它,我不明白你的意思,请澄清。”Prelude.showShowshowshow :: Stack (Stack (Stack ...)) -> Stringshow :: (Show a) => Stack a -> String

可能您的意图是:

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

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

于 2016-01-06T18:00:44.613 回答