Creating Instance of Eq for custom data type in Haskell - haskell

I have made some custom Data types for number representation in Haskell, now I want to implement Eq instances for it, but I am somehow stuck. So I have already made:
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg -- Pos fuer Positive, Neg fuer Negative
newtype Numeral = Num (Sign,Digits)
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
Now I want to check out the Sign in my custom type Numeral so I tried this:
instance (Eq Sign) => Eq (Numeral) where
(==) Num(x,_)== Num(y,_) = x==y
But I get this error: Parse error in pattern : (==)

Mostly putting what I've already written in the comments in a more fleshed out form:
There are a few problems with your code:
You have to indent the code under the instance declarations. That way you tell the compiler what code belongs to the instance declaration.
In the following line you are asking for a type class constraint on a concrete type (Eq Sign =>). This is not possible in standard Haskell and even if you were to follow the compiler instructions and enable the FlexibleInstances language extension it wouldn't make sense.
instance (Eq Sign) => Eq (Numeral) where
Type class constraints are only used for type variables. For example:
double :: Num a => a -> a
double x = x + x
Here we say, that the function double only works for all types that implement Num. double :: Num Int => Int -> Int on the other hand is redundant, because we already know, that Int has a Num instance. The same for Eq Sign.
For instances such constraints only make sense, if the type you are writing an instance for contains another polymorphic type. Fox example instance Ord a => Ord [a]. Here we would use the Ord instance of the elements of the list to lexiographically order lists.
You can define (==) either in infix or prefix form, but not both. So either (==) (Num (x,_)) (Num (y,_)) = x == y or Num (x,_) == Num (y,_) = x == y.
Newtyping tuples to create a product type is rather strange. Newtypes are usually used if you want to use the functionality that is already present for the more complex underlying type. However here that is not the case, you just want a normal product of Digits and Sign.
You are only comparing the Sign of the numbers. While technically a valid Eq instance, I think you also want to compare the digits of the number probably truncating leading zeros. In the code below I didn't truncate zeros though, to keep it simple.
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg
data Numeral = Num Sign Digits
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
instance Eq Numeral where
Num s1 x1 == Num s2 x2 = s1 == s2 && x1 == x2

Related

How do I correctly implement an instance Eq for a data type with constructors?

I am implementing an instance Eq for MyNum data type that has Fractions and Mixed Numbers as data constructors (each one with its own arguments).
I am also using a helper function to convert from MyNum to Rational. This should help me reduce fractions when doing comparisons in the instance Eq.
The problem is I am getting stuck when creating the instance Eq and I am not sure whether I also have to define a new class Eq for the MyNum data type. The general purpose of the Eq is to compare whether two fractions are equal when simplified with the helper method. Here is what I have so far:
Data Type and Constructors:
data MyNum = Fraction {num :: Integer, denom :: Integer}
| Mixed {whole :: Integer, num:: Integer, denom :: Integer}
Helper:
helper :: MyNum -> Rational
helper (Fraction num denom) = (fromIntegral num ) / (fromIntegral denom)
Current Eq:
instance (Eq n d) => Eq (MyNum n d) where
Fraction n d == Fraction n d = True
-- Mixed _ _ _ == Mixed _ _ _ = True
The above Eq code throws the following error:
MyNum.hs:29:16: error:
* Conflicting definitions for `d'
Bound at: MyNum.hs:29:16
MyNum.hs:29:32
* In an equation for `=='
|
29 | Fraction n d == Fraction n d = True
| ^^^^^^^^^^^^^^^^^
The reason this happens is because you use n and d twice in the head of your == method definition, which is not allowed.
Both Fraction n d and Fraction n d in Fraction n d == Fraction n d = True are patterns, and using the same variable in more than one pattern on the left of the = sign in not allowed.
You would also need to write the type constraints as (Eq n, Eq d) =>…, and not Eq n d, but here it makes no difference since you do not use type parameters anyway, so no Eq constraint is needed at all -- the type of the values used by your MyNum type, which are all Integers, already is an instance of Eq:
instance Eq MyNum where
Fraction n1 d1 == Fraction n2 d2 | n1 == n2 && d1 == d2 = True
-- …
Prolog, which works with unification indeed allows us to use the same variable multiple times in the head, to indicate equality.
But Haskell works with pattern matching, and it is therefore not entirely clear what reusing the same variable would mean, especially since not every type is an instance of Eq.
You might want to exploit your helper function to convert both MyNums into Rationals so that you can compare them:
instance Eq MyNum where
x == y = helper x == helper y
Your type MyNum does not take any parameters, so you can't write Eq (MyNum n d). The n and d are values, arguments for the Fraction data constructor, not the type. Since these values are handled by the helper, we don't need to care about them in the instance definition either.
Note that, for the above instance to work, helper must deal with both forms of number, Fraction and Mixed.
helper:: MyNum -> Rational
helper (Fraction num denom) = fromIntegral num / fromIntegral denom
helper (Mixed whole num denom) = ...

Haskell: "Non type-variable argument in the constraint: Eq Bit" and "No instance for (Eq Bit) arising drom a use of '=='"

data Bit = One
| Zero
deriving Show
type Bits = [Bit]
bits2String :: Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
| x == Zero = "0" ++ bits2String xs
This Code causes following error message:
No instance for (Eq Bit) arising drom a use of '=='
For this error you can find a lot of solutions on SO. They always say you need to add Eq like that:
bits2String :: (Eq Bit) => Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
| x == Zero = "0" ++ bits2String xs
But this doesnt work for me and causes following error
Non type-variable argument in the constraint: Eq Bit
(Use FlexibleContexts to permit this)
{-# LANGUAGE FlexibleContexts #-} doesnt work either.
The original error message is the key one:
No instance for (Eq Bit) arising drom a use of '=='
This arises because you are using the == operator, which is only available for instances of the Eq typeclass - and you haven't given such an instance.
That's easily fixed though. For one you can easily provide the instance manually:
instance Eq Bit where
One == One = True
Zero == Zero = True
_ == _ = False
I wouldn't recommend that you do that though. You can ask Haskell to generate that exact instance for you by simply adding a deriving clause to the type definition. In fact you're already using one, so you can just add Eq to the list of instances you want to derive:
data Bit = One
| Zero
deriving (Show, Eq)
Adding this instance is a good idea in general, because you might well need to compare Bits for equality at some point, especially when working with lists of them - many list functions such as elem depend on Eq instances for their members.
But you can rewrite your bits2String function to not need an Eq instance at all, by pattern matching on the two data constructors:
bits2String :: Bits -> String
bits2String [] = ""
bits2String (One:xs) = "1" ++ bits2String xs
bits2String (Zero:xs) = "0" ++ bits2String xs
In fact, you've basically reimplemented the map function here, so what I would likely do is to define:
bitToChar :: Bit -> Char
bitToChar Zero = '0'
bitToChar One = '1'
(especially as it's the kind of general utility function that you may well want for other things)
and then
bits2String = map bitToChar
None of those require an Eq instance - but it's likely a good idea to derive it anyway, for the reasons I mentioned.
You make use of x == Zero, so of the (==) :: Eq a => a -> a -> Bool function, but you did not make Bit an instance of Eq. You can do so by adding it to the deriving clause, such that Haskell can automatically implement an instance of Eq for your Bit data type:
data Bit = One
| Zero
deriving (Eq, Show)
By default two items are the same if the data constructor is the same, and the parameters (but here your data constructors have no parameters, so it will only check equality of the data constructors).
That being said, you do not need these to be an instance of Eq, you can use pattern matching instead. Indeed:
bits2String :: Bits -> String
bits2String = map f
where f Zero = '0'
f One = '1'
Here we make use of map :: (a -> b) -> [a] -> [b] to convert a list of items to another list by applying a function to each of the items in the original list. Since Bits is a list of Bits, and String is a list of Chars, we can thus map each Bit to a Char to obtain a String of '0's and '1's for the Zero and Ones respectively.

Haskell Eq between different types

I need to use this data structure data D = C Int Float and I need to compare it with an Int, for example a::D == 2.
How can I create an instance to define this kind of Eq ?
Thank you!
I would implement a projection:
getInt :: D -> Int
getInt (C i _) = i
and then compare with it:
getInt myD == 5
you can even include this into a record:
data D = C { getInt :: Int, getFloat :: Float }
if you like
You can't; == has signature a -> a -> Bool, so it can't be used like this.
Using the convertible package you can define
(~==) :: (Convertible a b, Eq b) => a -> b -> Bool
x ~== y = case safeConvert x of
Right x' -> x' == y
Left _ -> False
(==~) :: (Convertible b a, Eq a) => a -> b -> Bool
(==~) = flip (~==)
instance Convertible Int D where ...
-- or D Int depending on what you have in mind
Without depending on convertible, you could just define a conversion function either from Int to D (and write a == fromInt 2) or vice versa.
A less recommended route (for this specific case I think it's simply worse than the first solution) would be to define your own type class, e.g.
class Eq' a b where
(=~=) :: a -> b -> Bool
instance Eq a => Eq' a a where
x =~= y = x == y
instance Eq' D Int where ...
etc.
This can be done, but I doubt you will want to do this. As Alexey mentioned the type of (==) is Eq a=>a->a->Bool, so the only way to make this work would be to make 2 have type D. This may seem absurd at first, but in fact numbers can be made to have any type you want, as long as that type is an instance of Num
instance Num D where
fromInteger x = C x 1.0
There are still many things to work out, though....
First, you need to fully implement all the functions in Num, including (+), (*), abs, signum, fromInteger, and (negate | (-)).
Ugh!
Second, you have that extra Float to fill in in fromInteger. I chose the value 1.0 above, but that was arbitrary.
Third, you need to actually make D an instance of Eq also, to fill in the actual (==).
instance Eq D where
(C x _) == (C y _) = x == y
Note that this is also pretty arbitrary, as I needed to ignore the Float values to get (==) to do what you want it to.
Bottom line is, this would do what you want it to do, but at the cost of abusing the Num type, and the Eq type pretty badly.... The Num type should be reserved for things that you actually would think of as a number, and the Eq type should be reserved for a comparison of two full objects, each part included.

What's the difference between the "data" and "type" keywords?

The data and type keywords always confuse me.
I want to know what is the difference between data and type and how to use them.
type declares a type synonym. A type synonym is a new name for an existing type. For example, this is how String is defined in the standard library:
type String = [Char]
String is another name for a list of Chars. GHC will replace all usages of String in your program with [Char] at compile-time.
To be clear, a String literally is a list of Chars. It's just an alias. You can use all the standard list functions on String values:
-- length :: [a] -> Int
ghci> length "haskell"
7
-- reverse :: [a] -> [a]
ghci> reverse "functional"
"lanoitcnuf"
data declares a new data type, which, unlike a type synonym, is different from any other type. Data types have a number of constructors defining the possible cases of your type. For example, this is how Bool is defined in the standard library:
data Bool = False | True
A Bool value can be either True or False. Data types support pattern matching, allowing you to perform a runtime case-analysis on a value of a data type.
yesno :: Bool -> String
yesno True = "yes"
yesno False = "no"
data types can have multiple constructors (as with Bool), can be parameterised by other types, can contain other types inside them, and can recursively refer to themselves. Here's a model of exceptions which demonstrates this; an Error a contains an error message of type a, and possibly the error which caused it.
data Error a = Error { value :: a, cause :: Maybe (Error a) }
type ErrorWithMessage = Error String
myError1, myError2 :: ErrorWithMessage
myError1 = Error "woops" Nothing
myError2 = Error "myError1 was thrown" (Just myError1)
It's important to realise that data declares a new type which is apart from any other type in the system. If String had been declared as a data type containing a list of Chars (rather than a type synonym), you wouldn't be able to use any list functions on it.
data String = MkString [Char]
myString = MkString ['h', 'e', 'l', 'l', 'o']
myReversedString = reverse myString -- type error
There's one more variety of type declaration: newtype. This works rather like a data declaration - it introduces a new data type separate from any other type, and can be pattern matched - except you are restricted to a single constructor with a single field. In other words, a newtype is a data type which wraps up an existing type.
The important difference is the cost of a newtype: the compiler promises that a newtype is represented in the same way as the type it wraps. There's no runtime cost to packing or unpacking a newtype. This makes newtypes useful for making administrative (rather than structural) distinctions between values.
newtypes interact well with type classes. For example, consider Monoid, the class of types with a way to combine elements (mappend) and a special 'empty' element (mempty). Int can be made into a Monoid in many ways, including addition with 0 and multiplication with 1. How can we choose which one to use for a possible Monoid instance of Int? It's better not to express a preference, and use newtypes to enable either usage with no runtime cost. Paraphrasing the standard library:
-- introduce a type Sum with a constructor Sum which wraps an Int, and an extractor getSum which gives you back the Int
newtype Sum = Sum { getSum :: Int }
instance Monoid Sum where
(Sum x) `mappend` (Sum y) = Sum (x + y)
mempty = Sum 0
newtype Product = Product { getProduct :: Int }
instance Monoid Product where
(Product x) `mappend` (Product y) = Product (x * y)
mempty = Product 1
With data you create new datatype and declare a constructor for it:
data NewData = NewDataConstructor
With type you define just an alias:
type MyChar = Char
In the type case you can pass value of MyChar type to function expecting a Char and vice versa, but you can't do this for data MyChar = MyChar Char.
type works just like let: it allows you to give a re-usable name to something, but that something will always work just as if you had inlined the definition. So
type ℝ = Double
f :: ℝ -> ℝ -> ℝ
f x y = let x2 = x^2
in x2 + y
behaves exactly the same way as
f' :: Double -> Double -> Double
f' x y = x^2 + y
as in: you can anywhere in your code replace f with f' and vice versa; nothing would change.
OTOH, both data and newtype create an opaque abstraction. They are more like a class constructor in OO: even though some value is implemented simply in terms of a single number, it doesn't necessarily behave like such a number. For instance,
newtype Logscaledℝ = LogScaledℝ { getLogscaled :: Double }
instance Num LogScaledℝ where
LogScaledℝ a + LogScaledℝ b = LogScaledℝ $ a*b
LogScaledℝ a - LogScaledℝ b = LogScaledℝ $ a/b
LogScaledℝ a * LogScaledℝ b = LogScaledℝ $ a**b
Here, although Logscaledℝ is data-wise still just a Double number, it clearly behaves different from Double.

Haskell Ord instance paradox on Eq

I want to be able to order Polynomes with comparing first by lenght (degree), second by coefficient. Polynomes are list of doubles with [1,2,3] = 3x²+2x+1 .
But if there is a zero as last element it should be dropped, so I wrote a function doing that called realPolynom. realPolynom [1,2,3,0] = [1,2,3]
Now, my Ord instance looks like:
instance Ord Polynom where
compare a b = compare ((realLength a), reverse (pol2list (realPolynom a))) ((realLength b), reverse (pol2list (realPolynom b)))
realLength is just Length of polynom without zeros as last.
pLength :: Polynom -> Int
pLength (Polynom(a)) = length a
realLength :: Polynom -> Int
realLength a = pLength(realPolynom(a))
pol2list is Polynom p = p
pol2list :: Polynom -> [Double]
pol2list (Polynom p) = p
Problem is:
[0,2,0] < [0,2,3] true, which is good
[0,2,0] < [0,2] false, also good
[0,2,0] > [0,2] false, also good
[0,2,0] == [0,2] false, which is not good! should be equal!
Instead of deriving Eq, you should probably write
instance Eq Polynom where
a == b = compare a b == EQ
The best solution might be to ensure that no leading zeroes ever turn up in the first place. I.e. instead of ever building polynomes manually from lists, you feed them to a "smart constructor" that eats away zeroes before packing the Polynome data type.
May seem a bit of a OO-ish thing to do, but sometimes this kind of encapsulation is just the way to go, even in functional languages.
Something like this should work:
instance Eq Polynom where
x == y = pol2list (realPolynom x) == pol2list (realPolynom y)
Unfortunately, in this case the derived Eq instance is not the intended one.

Resources