问题
I'm new in functional programming and I'm trying to create and show a Stack with Haskell. I'd like my program to show me the Stack I'm building with it. This is my code:
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)
With "show (push 1 empty)" I'd expect an answer (more or less) like: " 1 <- | " But I'm not able to compile the code. When I try it shows the following error:
[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.
I understand the error where program could confuse the "show" from Prelude with an "show" defined by be, but I cannot see that error in my code. Besides, some mates have the same code, and the program works well.
There is something I have to change or I have missed?
Thanks!
回答1:
So the first problem is that you've got a `
character in the code you pasted for us. Your second problem is that you don't need to indent all of the lines in the module; most Haskell modules that I see will not indent the body of the module. Your third problem is that you do not need parentheses around show a
and show b
: precedence in Haskell is really simple; parentheses always take top priority, followed by function application (left-associative or "greedy nom", a function always gobbles up the first thing that it sees in front of it), followed by operators in their defined precedence, followed by special syntactic forms like \a ->
, let
, do
, where
. Those are generally aesthetic concerns but you probably still care.
Your final problem is here:
instance Show a => Show (Stack a) where
show EmptyStack = "|"
show (Stk a b) = (show a) ++ " <- " ++ (show b)
You want Haskell to turn this into the single statement:
instance Show a => Show (Stack a) where show tmpvar = case tmpvar of { EmptyStack -> "|"; Stk a b -> show a ++ " <- " ++ show b }
However Haskell has instead turned this into two separate lines:
instance Show a => Show (Stack a) where {}
show tmpvar = case tmpvar of { EmptyStack -> "|"; Stk a b -> show a ++ " <- " ++ show b }
So the multiple-definition is correctly converted into a case-dispatch, but it's not put within the curly braces above! So, you can omit curly braces {}
by using whitespace to indent lines. After where
, Haskell does not see any explicit {}
so it starts looking for indented lines, and it sees 0 of them, so it converts the clause to where {}
(thanks @chi).
Without being in curly braces, either because of indentation or not, that new line defines a different function, Stack.show
, distinct from the imported Prelude.show
that belongs to the Show
typeclass. The problem is that it also references a function called show
, which is now ambiguous: is this a recursive call for a function with infinite type show :: Stack (Stack (Stack ...)) -> String
or a dispatching call for a function with finite type show :: (Show a) => Stack a -> String
? Before it even tries to figure out those types it says "stop it, I don't know what you mean, please clarify."
Probably what you intended was instead:
instance Show a => Show (Stack a) where
show EmptyStack = "|"
show (Stk a b) = show a ++ " <- " ++ show b
This indentation clues the Haskell compiler to accepti the two following statements into the where
clause.
来源:https://stackoverflow.com/questions/34635468/ambiguous-occurrence-in-haskell-with-show