2

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.

3
  • Two lists having the same string presentation does not mean the two objects are equivalent. You will need to define your own instance of Eq for the CatLista. Commented Dec 8, 2021 at 17:42
  • Define toList :: CatLista a -> [a] first, then the Show instance is a trivial composition of toList and show for lists. Commented Dec 8, 2021 at 18:25
  • Your definition assumes that the string representation of a Conc value is the concatenation of the string representations of the two halves, rather than just the elements of the two halves. Commented Dec 8, 2021 at 18:28

2 Answers 2

4

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
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the answer. One little question about your answer with you could help me: When you do ca == cb = toLista ca == toLista cb you are meaning that, two random CatLista (ca and cb) are equal when their representation are equal (toLista ca == toLista cb) ? Thanks again
@AnderCarrera: toLista ca converts a CataLista to a list, so the two are equivalent if these are equivalent as list. This function thus not says that two CataListas are equivalent if they have the same show, although since you both define it in terms of toLista that will be the case here.
4

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.