Search code examples
haskellnestedalgebraic-data-types

Type casting when working with nested data structures


I have the following data structures defined:

data Operator = Plus | Times | Minus deriving (Eq,Show)
data Variable = A | B | C deriving (Eq,Show)
newtype Const = D Numeral deriving (Eq,Show)
data CVO = Const | Variable | Operator deriving (Eq,Show)
type Expr = [CVO]

I have defined the following function:

eval2 :: Expr -> Integer
eval2 x = helper x

I would like to check if an element of the CVO list (Expr) is either an instance of Const, Variable or Operator (this works) and I would like to implement varying code for the specific type of the instance (e.g. Plus, Times, Minus for Operator).

helper :: Expr -> Integer
helper [] = 2
helper (x:xs) 
    | x == Operator && x == Plus = 1

I cannot compare x to Plus, because it expects x to be of type CVO.

Couldn't match expected type ‘CVO’ with actual type ‘Operator’

Is it somehow possible to cast x to be an instance of Operator in order to do the comparison?


Solution

  • A value can't have two different types at the same time. If x is a CVO you can't use == to compare it to Plus which is an Operator.

    At the moment the type CVO consists of three constant values called Const, Variable and Operator. I'm guessing you actually wanted it to contain values of the type Const, Variable or Operator. You do that by declaring arguments to the constructors.

    data CVO = Const Const  -- a constructor whose name is Const and contains a value of type Const
             | Var Variable  -- a constructor named Var containing a Variable
             | Op Operator  -- a constructor named Op containing an Operator
    

    A given value of type CVO must have been built from one of those three constructors, containing a value of the correct type. You can test which constructor was used to create the CVO, and simultaneously unpack the value, using pattern matching. Something like this:

    helper :: Expr -> Integer
    helper [] = 0
    helper (Op o:xs)  -- because we matched Op, we know o :: Operator
        | o == Plus = 1
        | otherwise = 2
    helper _ = 3