0

I have a list of commands ([Command]) which looks like [forward 15, left 20, right 10]. I want to add forward 15 to [Command] whenever I see a forward 15 command. I used elem and == to compare whether the element is forward 15 or not but it gives me No instance for (Eq Command) arising error. Also, in another function, I want to add [left 15, forward 15, forward 15, right 15, right 15, forward 15, forward 15, left 15] to [Command] whenever I see 4 consecutive forward 15 commands. Thus my question is how to compare functions, because forward is a function and I can't compare it using elem or ==.

Command is defined as a type, not as a data, hence I can't use deriving Eq.

type Command = Funcs -> (Picture, Funcs)

data Funcs = Funcs {pen :: Bool, angle :: Float, point :: Point, penColor :: Color} deriving (Eq, Show)

forward :: Float -> Command
forward x = ....
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
Bhushan Oza
  • 112
  • 1
  • 10

2 Answers2

8

I recommend making a new data type for commands, and an interpreter into the Command semantic domain. For example:

data ReifiedCommand
    = Forward Float
    | Backward Float
    | Left Float
    | Right Float
    deriving (Eq, Ord, Read, Show)

interpret :: ReifiedCommand -> Command
interpret (Forward x) = forward x
interpret (Backward x) = backward x
interpret (Left x) = left x
interpret (Right x) = right x

Now you may compare ReifiedCommands for equality and do whatever inspection you need to do to build a suitable [ReifiedCommand], and then all at once at the end you may interpret these into a [Command] (or, more likely I think, even a single Command).

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • I added `DForward Float` to `Reified Command` and `interpret (DForward x) = forward (2*x)` to `interpret`. Then I used `replace [Forward] [DForward] x`. But it gave me error `No instance for (Eq (Float -> ReifiedCommand)) arising from a use of ‘replace’ ` – Bhushan Oza May 29 '19 at 04:08
  • 2
    That sounds like a new question - none of those elements were presented in the above. Daniel just gave you a solution which is basically "Don't compare functions, compare the inputs" and you just went right back to trying to compare functions. EDIT: stated another waay, you can't compare `DForward` but you can compare the fully-applied form such as `DForward 2`. – Thomas M. DuBuisson May 29 '19 at 04:55
  • @BhushanOza Don't do that. Instead, replace `Forward foo` with `Forward (foo*2)`. (You may not be able to reuse the exact `replace` function you have.) – Daniel Wagner May 30 '19 at 14:06
0

You might be missing a deriving clause in your data definition.

Prelude> data Command = Forward Int | Left Int | Right Int deriving (Eq, Show)
Prelude> Forward 15 == Forward 15
True

If you do not have the deriving clause you will see

No instance for (Eq Command) arising from a use of ‘==’

By the way, while it is true that Forward happens to be a (constructor) function, you want to make sure you are doing == comparisons not on functions themselves (you can't do this in Haskell) but rather on the result of applying the function. So you can never compare

Forward == Forward

because the type of Forward is Int->Command (a function) but you can compare

Forward 15 == Forward 15

as long as you associate the type Command with the Eq typeclass.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232