Home > Software design >  How to maintain state while adding to Stack in Haskell
How to maintain state while adding to Stack in Haskell

Time:10-02

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 type State a -> a -> State a. So far so good.

  • When addToStack is called with a value which matches the pattern State (Stack element), do the following. -- This is not good. Since Stack is a type, not a constructor, this makes no sense. It's like trying to pattern match on String by doing f (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.

  • Related