I have a State defined like given below:
newtype State a = State Stack
data Stack = Active [Maybe Int] | Inactive [Maybe Int]
Where the State is a State Stack where each Stack can be either Active or Inactive list of Maybe Ints. Next an empty State is created as given:
empty :: State a
empty = State (Active [])
Now I want to add an element to the State I tried going:
addToStack :: State a -> a -> State a
addToStack State(Stack element) a =
State(Stack element : a)
I used the word Stack to perserve the Stack portion of the State, adding an element to the State should not change a State from active to Inactive or vice versa. Is there a better way to do this? Because right now it gives me:
Not in scope: data constructor ‘Stack’
CodePudding user response:
When you write
data Stack = Active [Maybe Int] | Inactive [Maybe Int]
You are doing two things. First, you are introducing a new type called Stack
. Next you are introducing two new terms (ie, values) called Active
and Inactive
. These values respectively have types:
Active :: [Maybe Int] -> Stack
Inactive :: [Maybe Int] -> Stack
Furthermore, these values are "special" in that Haskell knows how to get the [Maybe Int]
back out of an Active
value (ie, they are constructors and can be pattern-matched on).
The point is that Stack
is only a type, not a value, and Active
and Inactive
are only values, not types. But when you write:
addToStack :: State a -> a -> State a
addToStack State(Stack element) a =
State(Stack element : a)
You are saying the following:
I want to create a function called
addToStack
with typeState a -> a -> State a
. So far so good.When
addToStack
is called with a value which matches the patternState (Stack element)
, do the following. -- This is not good. SinceStack
is a type, not a constructor, this makes no sense. It's like trying to pattern match onString
by doingf (String x) = ...
. No can do.
What you want is something like the following:
addToStack :: State a -> a -> State a
addToStack State(Active elements) a = ...
addToStack State(Inactive elements) a = ...
nb. There is a common practice in Haskell called punning wherein a constructor is given the same name as its related type, which unfortunately makes this mixup very easy to fall into.