I need to implement a general stack for something I'm working on. This stack should be able to hold elements of different types. For example, (1, 'c', True, "Strings"). The functions to be supported are top, pop and push.
Tuples are the most natural idea for this.
push x s = (x,s)
pop s = snd s
top s = (fst s, s)
But I need to support the empty stack too. Here, pop and top are not defined on (). So I tried creating a new type.
data Stack = Empty | forall x. Cons (x, Stack)
push x s = Cons (x,s)
pop s = case s of
Empty -> Left s
Cons (x, y) -> Right y
top s = case s of
Empty -> (Left (), s)
Cons (x,y) -> (Right x, s)
Here, top gives me an error:
Couldn't match expected type ‘b’ with actual type ‘x’
because type variable ‘x’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor
Cons :: forall x. (x, Stack) -> Stack,
in a case alternative
at try.hs:11:9-18
Relevant bindings include
x :: x (bound at try.hs:11:15)
top :: Stack -> (Either () b, Stack) (bound at try.hs:9:1)
In the first argument of ‘Right’, namely ‘x’
In the expression: Right x
If I work around this with:
data Stack x = Empty | forall y. Cons (x, Stack y)
I get the same error for pop.
I also tried adding this:
type AnyStack = forall x. Stack x
but again get a similar error:
Couldn't match expected type ‘b’ with actual type ‘Stack y’
because type variable ‘y’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor
Cons :: forall x y. (x, Stack y) -> Stack x,
in a case alternative
at try.hs:8:9-19
Relevant bindings include
y :: Stack y (bound at try.hs:8:18)
pop :: Stack t -> Either (Stack t) b (bound at try.hs:6:1)
In the first argument of ‘Right’, namely ‘y’
In the expression: Right y
Could anyone help me out with the right type signatures or type definition for this kind of a stack? Or maybe point me to some good reference related to this?
Thanks a lot in advanced!
Edit:
It'd be perfect if I'd also be able to include a get function for this stack. Given an integer i, and a stack s, get would return the i-th element of s. I was hoping that probably I'd be able to do that myself once push, pop and top are sorted out, but I'm still unable to. Any ideas regarding this guys?
Do you need to have it untyped? If you're willing to use advanced GHC features, you can do something like this:
A few uses in ghci look like this:
Note that this representation has the nice feature that it's a compile-time error to call
pop
ortop
on an empty stack. It is slightly harder to work with, though, since you always need to prove you're calling it with a non-empty stack. It's good for preventing bugs, but sometimes requires more bookkeeping to convince the compiler you got it right. It's not a sure thing that this representation is a good choice. It depends on the use case.