3

I've been trying to implement an instance Eq for a Function but I keep getting Syntax erros and can't find anywhere how it's supposed to be. A function is equal if for every input it throws the same output. So I tried just going through every input and check if the results are equal.

newtype Funktion = Fkt { f :: Zahlraum_0_10 -> Zahlraum_0_10 }

data Zahlraum_0_10 = N | I | II | III | IV | V | VI
                     | VII | VIII | IX | X | F deriving (Eq,Ord,Show)

instance Eq Funktion where
  (==) (Fkt f2 _) (Fkt f1 _) = f2 I == f1 I && f2 II == f1 II && f2 III == f1 III &&
  f2 IV == f1 IV && f2 V == f1 V && f2 VI == f1 VI && f2 VII == f1 VII && f2 VIII == f1 VIII &&
  f2 IX == f1 IX && f2 X == f1 X && f2 N == f1 N && f2 F == f1 F
Pramox Lol
  • 57
  • 4
  • 5
    Two problems: In your pattern matching, `Fkt` has only one argument but you match two. (Get rid of the underscores after `f2` and `f1`). Second: Indentation. Make sure the 3rd and 4th lines in your `Eq` declaration are indented a bit to the right. But more importantly, there are better ways to write what you want: Make your datatype instance of `Enum` and `Bounded`, and then you can just do `and [f1 x == f2 x | x <- [minBound .. maxBound]]` – alias Nov 15 '21 at 18:29
  • @alias Right, but doesn't the list comprehension return a list of Bools? I want just a single Bool, right? – Pramox Lol Nov 15 '21 at 18:47
  • 1
    Note the call to `and` over the result. `and [...]`, which conjuncts all the bools. – alias Nov 15 '21 at 18:47
  • 1
    @PramoxLol: list comprehension indeed returns a *list* of `Bool`s, but the `and` function will turn that into a single `Bool`: `True` if all `Bool`s in the list are `True` and `False` otherwise. – Willem Van Onsem Nov 15 '21 at 18:48

1 Answers1

0

The error is about the use of the Fkt data constructor: your Fkt data constructor has only one attribute: the function f that maps a Zahlraum_0_10 to a Zahlraum_0_10. You thus unpack the function out of the Fkt with Fkt f1, so without a _ as second attribute:

It might also be better to work with all :: Foldable f => (a -> Bool) -> f a -> Bool since this reduce the amount of code (and makes it less error prone) to compare the two functions:

instance Eq Funktion where
  Fkt f1 == Fkt f2 = all go [N, I, II, III, IV, V, VI, VII, VIII, IX, X, F]
    where go x = f1 x == f2 x

We can also work with liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c instead of defining a go function:

import Control.Applicative(liftA2)

instance Eq Funktion where
  Fkt f1 == Fkt f2 = all (liftA2 (==) f1 f2) [N, I, II, III, IV, V, VI, VII, VIII, IX, X, F]

We do not have to define the list of values explicitly: since all the data constructors have no parameters, one can easily make these an instance of Enum and Bounded:

data Zahlraum_0_10 = N | I | II | III | IV | V | VI
                     | VII | VIII | IX | X | F deriving (Bounded, Enum, Eq, Ord, Show)

In that case we can determine if the two functions map to the same value for each parameter with:

import Control.Applicative(liftA2)

instance Eq Funktion where
  Fkt f1 == Fkt f2 = all (liftA2 (==) f1 f2) [minBound ..]
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555