Home > other >  Haskell Data Type Instance as operator
Haskell Data Type Instance as operator

Time:12-09

I have recieved a exercice to learn about data types in haskell and I can't figure out how to solve this one.

They got me a data like : data CatLista a = Nil | Unit a| Conc (CatLista a) (CatLista a) deriving Eq and I need to make the data types become: Nil -> [] , Unit x -> [x] , Conc -> same operator as ( )

So if you run Conc (Unit 9)(Conc (Unit 5) (Unit 3)) == Conc (Conc (Unit 9) (Unit 5))(Conc (Unit 3) Nil) should give true and Conc (Unit 9)(Unit 3) == Conc (Unit 3) (Unit 9) should give false.

I already tried instancing the show class like this:

instance Show a => Show (CatLista a) where
    show a = case a of
        Nil -> []
        Unit x -> "["    show x    "]"
        Conc Nil dos -> show dos
        Conc uno Nil -> show uno 
        Conc uno dos -> "["   show uno    ","    show dos    "]"

I'm quite new to haskell so I may not know some basics, because I can't understand why if I run it (beeing Conc uno dos -> show uno show dos) with the same command as bellow Conc (Unit 9)(Conc (Unit 5) (Unit 3)) == Conc (Conc (Unit 9) (Unit 5))(Conc (Unit 3) Nil) it still returns False even tough they both return the same [9][5][3] with my show instance.

EDIT

Thanks to you I made it, it know returns correctly the values like intended with this code:

toLista :: Eq a => CatLista a -> [a]
toLista Nil = []
toLista (Unit x) = [x]
toLista (Conc a b) 
                    | a == Nil = toLista b 
                    | b == Nil = toLista a
                    | otherwise = (  ) (toLista a) (toLista b)

instance (Show a,(Eq a)) => Show (CatLista a) where 
    show a= show (toLista a)

But still I dont know why if I try the same comparation it still returns False, even tough I get returned the same [9,5,3].

This is probably due to my lack of knowledge in Haskell, sorry about that.

CodePudding user response:

Two values are not equivalent if these produce the same String when calling show on these. The (==) :: Eq a => a -> a -> Bool function is implemented by the Eq typeclass. You thus need to implement the instance of Eq for your CatLista yourself.

The default implementation for Eq, if you use deriving Eq is that two values are the same if they have the same data constructor, and the parameters are elementwise equivalent by calling (==) on these.

You thus can implement the instance for Eq yourself with:

data CatLista a = Nil | Unit a| Conc (CatLista a) (CatLista a) -- ← no deriving Eq

instance Eq a => Eq (CatLista a) where
    ca == cb = toLista ca == toLista cb

CodePudding user response:

Because you include deriving Eq in the data declaration, you're telling the compiler to generate a default equality method. The compiler cannot read your mind and know that you intend to represent lists via concatenation of sublists.

You know you intend Conc [1, 2] [3] to represent the same list as Conc [1] [2, 3]1; either should be regarded as representing [1, 2, 3]. The compiler does not know this. The generated equality method sees that in one case we have [1, 2] in the first field of the Conc constructor, and in the other case we have [1]. Those two things aren't equal, so the default equality method says that the whole structure is not equal either.

To avoid that, stop messing around with the Show instance. Show is for converting a CatList to a String of code that would build it. It has nothing to do with testing equality. There's no possible way you can change the outcome of == by defining a Show instance.

You need to remove deriving Eq from the data declaration. That will mean the compiler doesn't generate a default equality method, so you can write your own one that does something different (compares whether two CatLists represent the same list rather than comparing whether they have the same structure).


1 I am abusing notation here to write the sublists using bracket syntax; this is not valid code, I'm just trying to make the difference in sub-structure more easily visible.

  • Related