Defining Ord instance for own datatype - haskell

Being new to Haskell I am having trouble to get an Order instance implemented for my datatype,
namely:
data Polynom = Polynom ([Double])
deriving Show
p0 = Polynom([3.9,4.2,2.7])
p1 = Polynom([0.0,0.2,-3.6,9.4])
Polynomes are being a list of doubles, where i.e. p0 = 2.7x² + 4.2x + 3.9. My problem is that I just couldn't figure out the correct syntax for declaring the various if-cases, starting something like:
instance Ord Polynom where
realLength(a) > realLength(b) = a > b
where if realLength(a)) == realLength(b) = compare lastElement(a) lastElement(b)
I know this is a really bad pseudo-code, but I hope you get the idea.
I would really appreciate any hints on how to get started, I think I can figure out the different cases myself!
Edit:
Figured instance Eq could be something like that, but compiler does not accept it.
instance Eq Polynom where
(realPolynom a) == (realPolynom b) = (Polynom a) == (Polynom b)
Code for realPolynom:
realPolynom :: Polynom -> Polynom
realPolynom (Polynom(m:ns))
| m==0.0 = realPolynom (Polynom(ns))
| otherwise = Polynom(m:ns)

You may be looking for
instance Ord Polynom where
compare (Polynom p) (Polynom q) = compare (length p, reverse p) (length q, reverse q)
this compares polynomials first by length (degree). When lengths coincide, coefficients are compared.
Note that this assumes the first coefficient (last in the list) of a polynomial is non-null. That is, Polynomial [0,1,0] is greater thanPolynomial [0,2] according to this ordering. You may wish to add a dropWhile (==0) to cope with this.

Related

Haskell nested lists with newtype

Disclaimer: I am new to working with haskell.
I am working with proving logical formulas in haskell. I have trouble understanding how to work with newtypes and datas properly.
I have defined the following types to represent logical formulas that have the structure: (a or b or c) and (d or e) and (f) etc.
data Literal x = Literal x | Negation x
deriving (Show, Eq)
newtype Or x = Or [Literal x]
deriving (Show, Eq)
newtype And x = And [Or x]
deriving (Show, Eq)
I want to write a function that can filter on the literals (i.e. take out certain a b or c based on some condition). Naively I thought this should be similar to filtering on [[Literal x]] but I cannot seem to get it to work.
My current method is something like:
filterLit :: Eq x => And x -> And x
filterLit = map (\(Or x) -> (filter (\(Lit l) -> condition l) x))
This doesn't type. I feel like I'm missing some syntax rules here. Let me know if you have suggestions on how I should approach it.
\(Or x) -> filter (\(Lit l) -> condition l) x
Let's check the type of this function.
The domain must have type Or x. That's OK.
The codomain is the result of filter, hence it is a list. Let's only write [....] for that.
Hence, the function is Or x -> [....].
If we map that, we get [Or x] -> [[....]]. This is not the same as the claimed type And x -> And x -- a type error is raised.
First, you want your lambda to have type Or x -> Or x. For that, you can use \(Or x) -> Or (filter .....).
Then, you want filterLit to be something like
filterLit (And ys) = And (map ....)
so that it has the right type.

Is there a way to bind the supressed type variable of an existential data type during pattern matching?

Using GADTs, I have defined a depth-indexed tree data type (2–3 tree). The depth is there to statically ensure that the trees are balanced.
-- Natural numbers
data Nat = Z | S Nat
-- Depth-indexed 2-3 tree
data DT :: Nat -> Type -> Type where
-- Pattern of node names: N{#subtrees}_{#containedValues}
N0_0 :: DT Z a
N2_1 :: DT n a -> a -> DT n a
-> DT (S n) a
N3_2 :: DT n a -> a -> DT n a -> a -> DT n a
-> DT (S n) a
deriving instance Eq a => Eq (DT n a)
Now, some operations (e.g. insertion) might or might not change the depth of the tree. So I want to hide it from the type signature. I do this using existential data types.
-- 2-3 tree
data T :: Type -> Type where
T :: {unT :: DT n a} -> T a
insert :: a -> T a -> T a
insert x (T dt) = case dt of
N0_0 -> T $ N2_1 N0_0 x N0_0
{- ... -}
So far so good. My problem is:
I don't see how I can now define Eq on T.
instance Eq a => Eq (T a) where
(T x) == (T y) = _what
Obviously, I would like to do something like this:
(T {n = nx} x) == (T {n = ny} y)
| nx == ny = x == y
| otherwise = False
I don't know how / whether I can bind the type variables in the patter match. And I am neither sure how to compare them once I get them.
(I suspect Data.Type.Equality is for this, but I haven't seen any example of it in use.)
So, is there a way to implement the Eq (T a) instance, or is there some other approach that is recommended in this case?
You should write a depth-independent equality operator, which is able to compare two trees even if they have different depths n and m.
dtEq :: Eq a => DT n a -> DT m a -> Bool
dtEq N0_0 N0_0 = True
dtEq (N2_1 l1 x1 r1) (N2_1 l2 x2 r2) =
dtEq l1 l2 && x1 == x2 && dtEq r1 r2
dtEq (N3_2 a1 x1 b1 y1 c1) (N3_2 a2 x2 b2 y2 c2) =
dtEq a1 a2 && x1 == x2 && dtEq b1 b2 && y1 == y2 && dtEq c1 c2
dtEq _ _ = False
Then, for your existential type:
instance Eq a => Eq (T a) where
(T x) == (T y) = dtEq x y
Even if in the last line the depths are unknown (because of the existential), it won't matter for dtEq since it can accept any depth.
Minor side note: dtEq exploits polymorphic recursion, in that recursive calls can use a different depth from the one in the original call. Haskell allows polymorphic recursion, as long as an explicit type signature is provided. (We need one anyway, since we are using GADTs.)
You could use Data.Coerce.coerce to compare the contents of the trees: as long as you label the depth parameter as phantom, it should be willing to give you coerce :: DT n a -> DT m a.
But this doesn't really solve the problem, of course: you want to know if their types are the same. Well, maybe there is some solution with Typeable, but it doesn't sound like much fun. Absent Typeable, it seems impossible to me, because you want two contradictory things.
First, you want that trees of different depths should be separate types, not intermixable at all. This means everyone who handles them has to know what type they are.
Second, you want that you can give such a tree to someone without telling them how deep it is, have them munge it around arbitrarily, and then give it back to you. How can they do that, if you require type knowledge to operate on them?
Existentials do not "suppress" type information: they throw it away. Like all type information, it is gone at runtime; and you've made it invisible at compile time too.
I'm also not sure your problem is just with Eq: how will you even implement functions like insert? It's easy for N0_0, because that is known to have type DT Z a, but for the other cases I don't see how you will construct a DT (S n) a to wrap in your T when you can't know what n was.

Haskell - create instance of class (how to do it right?)

I read the chapter about that topic in "learn you a haskell" and tried to find some hints on different websites - but are still unable to solve the following task.
Im a haskell newbie (6 weeks of "experience") and its the first time I have to work with instances.
So here is the task, my code has to pass the HUnit tests and the end. I tried to implement the instances but it seems like I´ve missed something there. Hope you can help me! THX
module SemiGroup where
{-
A type class 'SemiGroup' is given. It has exactly one method: a binary operation
called '(<>)'. Also a data type 'Tree' a newtype 'Sum' and a newtype 'Max' are
given. Make them instances of the 'SemiGroup' class.
The 'Tree' instance should build a 'Branch' of the given left and right side.
The 'Sum' instance should take the sum of its given left and right side. You need
a 'Num' constraint for that.
The 'Max' instance should take the maximum of its given left and right side. You
also need a constraint for that but you have to figure out yourself which one.
This module is not going to compile until you add the missing instances.
-}
import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?=))
-- | A semigroup has a binary operation.
class SemiGroup a where
(<>) :: a -> a -> a
-- Leaf = Blatt, Branch = Ast
-- | A binary tree data type.
data Tree a = Leaf a
| Branch (Tree a) (Tree a)
deriving (Eq,Show)
-- | A newtype for taking the sum.
newtype Sum a = Sum {unSum :: a}
-- | A newtype for taking the maximum.
newtype Max a = Max {unMax :: a}
instance SemiGroup Tree where
(<>) x y = ((x) (y))
instance SemiGroup (Num Sum) where
(<>) x y = x+y
instance SemiGroup (Eq Max) where
(<>) x y = if x>y then x else y
-- | Tests the implementation of the 'SemiGroup' instances.
main :: IO ()
main = do
testresults <- runTestTT tests
print testresults
-- | List of tests for the 'SemiGroup' instances.
tests :: Test
tests = TestLabel "SemiGroupTests" (TestList [
Leaf "Hello" <> Leaf "Friend" ~?= Branch (Leaf "Hello") (Leaf "Friend"),
unSum (Sum 4 <> Sum 8) ~?= 12,
unMax (Max 8 <> Max 4) ~?= 8])
I tried something like:
class SemiGroup a where
(<>) :: a -> a -> a
-- Leaf = Blatt, Branch = Ast
-- | A binary tree data type.
data Tree a = Leaf a
| Branch (Tree a) (Tree a)
deriving (Eq,Show)
-- | A newtype for taking the sum.
newtype Sum a = Sum {unSum :: a}
-- | A newtype for taking the maximum.
newtype Max a = Max {unMax :: a}
instance SemiGroup Tree where
x <> y = Branch x y
instance Num a => SemiGroup (Sum a) where
x <> y = x+y
instance Eq a => SemiGroup (Max a) where
x <> y = if x>y then x else y
But there a still some failures left! At least the wrap/unwrap thing that "chi" mentioned. But I have no idea. maybe another hint ? :/
I fail to see how to turn Tree a into a semigroup (unless it has to be considered up-to something).
For the Sum a newtype, you need to require that a is of class Num. Then, you need to wrap/unwrap the Sum constructor around values so that: 1) you take two Sum a, 2) you convert them into two a, which is a proper type over which + is defined, 3) you sum them, 4) you turn the result back into a Sum a.
You can try to code the above yourself starting from
instance Num a => Semigroup (Sum a) where
x <> y = ... -- Here both x and y have type (Sum a)
The Max a instance will require a similar wrap/unwrap code.
A further hint: to unwrap a Sum a into an a you can use the function
unSum :: Sum a -> a
to wrap an a into a Sum a you can use instead
Sum :: a -> Sum a
Note that both functions Sum, unSum are already implicitly defined by your newtype declaration, so you do not have to define them (you already did).
Alternatively, you can use pattern matching to unwrap your values. Instead of defining
x <> y = ... -- x,y have type Sum a (they are wrapped)
you can write
Sum x <> Sum y = ... -- x,y have type a (they are unwrapped)
Pay attention to the types. Either manually, or with some help from GHCi, figure out the type of the functions you are writing -- you'll find they don't match the types that the typeclass instance needs. You'll use wrapping and unwrapping to adjust the types until they work.

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.

How to use modifiers with Quickcheck (Positive in my case)

I've a function, rev, that returns some value for a type that is in three typeclasses:
rev :: (Integral a, Show a, Read a) => a -> a
rev = read . reverse . show
I'd like to test some property about it with quickcheck. Though, I'm not interested in testing negative values of Integral types because I'm using Integer by lack of a Natural type in the base library. So I thought, let's take the opposite of the value generated when the value generated is negative and I'll be fine:
prop_id :: (Integral a, Show a, Read a) => Positive a -> Bool
prop_id n | n >= 0 = (rev.rev) n == n
| otherwise = let n' = -n in (rev.rev) n' == n'
(the property tested isn't important here - in particular it doesn't hold for very basic values and I'm aware of that, it's not the subject of this question)
Then I ran into the Positive modifier and thought that although my test was now functionning, it'd be nice to implement it in a nicer way. So I tried:
prop_id :: (Integral a, Show a, Read a) => Positive a -> Bool
prop_id n = (rev.rev) n == n
I must admit I was surprised when it compiled. But then an error popped when running the test:
*** Failed! Exception: 'Prelude.read: no parse' (after 1 test):
Positive {getPositive = 1}
So I thought, "mmk, must declare this Positive thing an instance of Read". So I did just that, but the instance is already declared in the quickCheck library it seems because ghci screamed at me.
And at this point I'm lost, for I do not find good documentation (if any).
Any pointer helping me to understand modifiers and other nice things in the quickcheck library will be appreciated.
The common way of using these modifiers is to pattern match on them, e.g.
prop_id :: (Integral a, Show a, Read a) => Positive a -> Bool
prop_id (Positive n) = (rev.rev) n == n
This way, n will have the underlying type.

Resources