Home > Back-end >  fmap replace literals in parse trees
fmap replace literals in parse trees

Time:12-13

I want to change all literals.

data Expressions a = ListExpression String[Expressions a]
| BinaryExpression String (Expressions a) (Expressions a)
| UnaryExpression String(Expressions a)
| Variables Variable
| Literals a
deriving Eq

Now i want to have all Literals changed to b, if the literals in c equals b. So example:


changeData 20 30 (Literals 100) = (Literals 100)
changeData 20 30 (Literals 20) = (Literals 30)

The expression itself should not be changed.

changeData :: (Eq a) => a -> a -> Expressions a -> Expressions a
changeData a b c 

I dont understand how to access it. I thought something like this:

 fmap (Literals b == Literals a) (\x -> if x == True = a else b) 

I thought like: Literals b == Literals a for each Expression. If true, then change to a, otherwise to b.

But like I wrote it down, its not working and I cant figure my mistake out.

Am im fundamentally missunderstanding something?

CodePudding user response:

First, your Functor instance is making up data constructors, rather than using the ones that were actually defined.

instance Functor Expressions where
     fmap f (Literals a) = Literals (f a)
     fmap f (Variables a) = Variables a
     fmap f (UnaryExpression a b) = UnaryExpression a (fmap f b)
     fmap f (BinaryExpression a b c) = BinaryExpression a (fmap f b) (fmap f c) 
     fmap f (ListExpression a b) = ListExpression a (fmap (fmap f) b)

Next, all you need is a function that checks if its argument is equal to a: if it is, return b; otherwise return the argument.

changeData a b c = fmap (\x -> if x == a then b else x) c

The definition of fmap already handles each of the data constructors for Expression; the function only needs to worry about the value extracted from a Literals value. (That is, f is only ever applied to a value in a Literals value; otherwise, it is just fmapped recursively until it reaches a Literals.)

CodePudding user response:

You can let Haskell derive the instance for the Functor typeclass with the DeriveFunctor GHC extension:

{-# LANGUAGE DeriveFunctor #-}

data Expressions a
  = ListExpression String [Expressions a]
  | BinaryExpression String (Expressions a) (Expressions a)
  | UnaryExpression String (Expressions a)
  | Variables Variable
  | Literals a
  deriving (Eq, Functor)

GHC will generate a Functor instance where it maps items of type a to type b by calling the functor function on these, and it will recurse on expressions with an a to map the a items wrapped in these subexpressions.

Then you can use fmap for changeData as @chepner says with:

changeData :: Eq a => a -> a -> Expressions a -> Expressions a
changeData a b = fmap (\x -> x == a then b else x)
  • Related