No instance for Eq - haskell

I have a custom data type Point Int Int and I need to compare it to another Point Int Int (with elem function).
Could you please tell me how to write Eq instance for this data type? Thanks.
type Result = [String]
data Point = Point Int Int
-- missing Eq instance
data Line = Line Point Point
drawField :: [Point] -> (Int, Int) -> Result
drawField positions (width, height) = let
check coordinates | elem coordinates positions = '#'
| otherwise = '.'
in [[check (Point rows cols) | cols <- [0..width-1]] | rows <- [0..height-1]]

If two Points are equal if all parameters are elementwise equal, then you can let Haskell derive the Eq instance with:
data Point = Point Int Int deriving Eq
If the points are equivalent if a more sophisticated test succeeds, you can define your own instance of Eq with:
instance Eq Point where
Point xa ya == Point xb yb = …
where … is an expression with Bool as type.

Related

Haskell Programming a graph

I'm almost there with this code the only difference is instead to adding n1 to the graph, I have to add the edges of n1 to the graph but I can't seem to figure out how.
Question: The file includes a function named insertEdge of type Eq a =>
(NodeID,NodeID) -> Graph a -> Maybe (Graph a) that inserts an
edge from the Node with the given NodeID in the first part of the tuple
to the Node with the given NodeID in the second part of the tuple.
If the edge already exists, it should NOT introduce a duplicate. If
the nodes corresponding to either of the given NodeIDs do not already
exist, the function should return Nothing.
`insertEdge :: Eq a => (NodeID,NodeID) -> Graph a -> Maybe (Graph a)
insertEdge _ (Graph []) = Nothing
insertEdge (n1,n2) g#(Graph graph)
| not containsBothNodes = Nothing
| otherwise = Just(Graph(insertE (n1,n2) graph))
where
containsBothNodes :: Bool
containsBothNodes = case(lookupNode n1 g) of
(Just _)->True
_ -> False
insertE (n1,n2) ((n0,es):graph)=
if (getNodeID n0)==n2
then
if es/=[]
then (n0,es):graph
**else (n0,es++[n1]):graph**
else (n0,es):insertE (n1,n2)graph
Description of the graph
newtype Graph a = Graph [(Node a,[NodeID])]
deriving (Show,Eq)
type NodeID = Int
data Node a = Node { getNodeID :: NodeID,
getNodeVal :: a }
deriving (Show,Eq,Ord)
nodeA,nodeB,nodeC :: Node Char
nodeA = Node 0 'A'
nodeB = Node 1 'B'
nodeC = Node 2 'C'
exGraph :: Graph Char
exGraph = Graph [(nodeA,[1,2])
,(nodeB,[])
,(nodeC,[1,2])]
`
I highlighted the part that I cannot figure out. Instead of adding n1, it should add the edges of n1

Haskell: Understanding custom data types

I am trying to make my own custom data type in Haskell.
I have the following data types:
type Length = Integer
type Rotation = Integer
data Colour = Colour { red, green, blue, alpha :: Int }
deriving (Show, Eq)
I am trying to make a custom data type that can be either one of the data types above. I have the following:
data Special
= L Length
| R Rotation
| Col Colour
deriving (Show, Eq)
However, I would like to be able to extract the Length, Rotation and Colour value if I have an instance of the Special data type.
If I had:
L length
Would length here be of type Special or of type Length? If length is of type Special is there any way to extract it so it's of type Length?
For example, is the following code valid?
takeL (x:xs)
| x == (L length) = length
Any insights are appreciated.
For the expression L length to be valid, length would have to be a Length (because L :: Length -> Special).
takeL (x:xs)
| x == (L length) = length
is not valid. Unless you've redefined length somewhere, length is a function [a] -> Int from the standard library, so L length is a type error.
I think what you're trying to do here is just pattern matching:
takeL (L length : xs) = length
The data type definition
data Special =
reads: Special is a new type such that to create a value of type Special,
L Length
call L l where l is a value of type Length; or
| R Rotation
call R r where r is a value of type Rotation; or
| Col Colour
call Col c where c is a value of type Colour.
To analyze a value of type Special, there are three cases to consider:
foo :: Special -> ...
foo val =
case val of
L l -> ...
l is a value of type Length, in the case val was actually L l; or
R r -> ...
r is a value of type Rotation, in the case val was actually R r; or
Col c -> ...
c is a value of type Colour, in the case val was actually Col c.
The case syntax in function definitions can also be expressed with the pattern based clauses:
foo :: Special -> ...
foo (L l) = ...
foo (R r) = ...
foo (Col c) = ...

How to check if coords(x,y) are valid on a board in Haskell

I have a function
isValid :: CoOrd -> Bool
Where CoOrd is a tuple pair (x,y)
The boards size is ['a'..'h'] ['1'..'8'] so I want to check if the given CoOrds are valid for this board (CoOrds x < ['a'..'h'], CoOrds y ['1'..'8'])
I'm fine with the logic of this question, its just the syntax as I'm new to haskell, so I'm looking for something like this
if (CoOrd(x _) == ['a'..'h'])
if (CoOrd(_ y) == ['1'..'8'])
return True
else return False
The basic approach is to use direct comparisons:
isValid :: CoOrd -> Bool
isValid (x,y) = x >= 'a' && x <= 'h' && y >= '1' && y <= '8'
A more advanced alternative is to exploit Data.Ix.inRange:
import Data.Ix
isValid :: CoOrd -> Bool
isValid = inRange (('a','1'),('h','8'))
You can also use elem, as others pointed out, but elem will scan the whole list and perform pointwise comparisons (8+8 comparisons, in the worst case), while the methods above will only do four comparisons.
Finally, a few comments on your original code:
Don't use return in Haskell unless you are writing monadic code
Don't use if condition then True else False -- that's noise, and it is equivalent to conditions. Consider using boolean operators instead, which is often simpler.
Why not make some new types for your X and Y coordinates so the type checker gives you a static guarantee that any CoOrd value is correct?
For example, I think you have type CoOrd = (Char,Int). Instead try:
data XCo = A | B | C | D | E | F | G | H deriving (Eq,Ord,Show,Enum)
data YCo = Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | Y8 deriving (Eq,Ord,Enum)
instance Show YCo where
show y = show (fromEnum y + 1)
type CoOrd = (XCo,YCo)
And now anywhere you were using character literals like 'a', 'b' etc you use A, B etc. Same with the numbers and the Y axis - 1 becomes Y1 etc.
isValid (x,y) = x `elem` ['a'..'h'] && y `elem` ['1'..'8']
In addition to the other answers instead of using tuples you may define a new type, for example ChessBoard.
Since you are in need of checking the validity of the entered position it might be wise to make it Maybe ChessBoard type as well.
Accordingly you may come up with something like
module ChessBoard (ChessBoard, chessBoard) where
data ChessBoard = CB Char Int deriving (Eq, Ord, Show)
chessBoard :: Char -> Int -> Maybe ChessBoard
chessBoard c n | elem c ['a'..'h'] && elem n [1..8] = Just (CB c n)
| otherwise = Nothing
Here as you may notice we are not exporting the data constructor CB Char Int so the only way to create your chess board position data is through the chessBoard function and there will be no illegal board positions.
I mean;
*Main> chessBoard 'a' 3
Just (CB 'a' 3)
*Main> chessBoard 'h' 9
Nothing
*Main> let pos = Just (CB 'a' 11) -- trying to assign an illegal position directly
<interactive>:259:17: error:
Data constructor not in scope: CB :: Char -> Integer -> a

How can I calculate the area of a triangle only with valid inputs?

I'm new to Haskell. I got this question from my assignment. It ask me to make this code work:
area_of_triangle :: Float
-> Float
-> Float
-> Maybe Float
I know how to do this without Maybe; it's like:
area_of_triangle :: Float -> Float -> Float -> Float
area_of_triangle a b c = sqrt(s*(s-a)*(s-b)*(s-c))
where
s = (a+b+c)/2
I guess the requirement would be if area_of_triangle=0.0, return Nothing (because such the triangle doesn't exist). But I don't know how to write this.
Three lengths can only form a triangle if the sum of each pair of lengths is greater than the other length. In the cases where that is not true, return Nothing. Otherwise, you can return Just a, where a is the length you calculate with your original formula.
area_of_triangle :: Float -> Float -> Float -> Float
area_of_triangle a b c = sqrt(s*(s-a)*(s-b)*(s-c))
where
s = (a+b+c)/2
area :: Float -> Float -> Float -> Maybe Float
area a b c
| ??? = Nothing
| ??? = Nothing
| ??? = Nothing
| otherwise = Just (???)
I leave it as an exercise to figure out what Boolean expressions replace the first three ???s, and what to replace the last ??? with.
Figured it out eventually
area_of_triangle :: Float -> Float -> Float -> Maybe Float
area_of_triangle x y z
| x+y>=z && x+z>=y && y+z>=x = Just (sqrt(s*(s-x)*(s-x)*(s-x)))
| otherwise = Nothing
where
s=(x+y+z)/2
I would break this up into three functions:
-- | Takes three numbers and indicates
-- whether they can be the lengths of
-- the sides of a (non-degenerate)
-- triangle.
triangleInequality :: (Num a, Ord a)
=> a -> a -> a -> Bool
triangleInequality x y z
| ??? &&
??? &&
??? = ???
| otherwise = ???
uncheckedArea :: RealFloat a
=> a -> a -> a -> a
uncheckedArea x y z = ???
area :: RealFloat a
=> a -> a -> a -> Maybe a
area x y z
| ??? = Just ???
| otherwise = Nothing
According to this draft article, you can improve the numerical stability of your calculation as follows:
area a' b' c'
| c - (a - b) <= 0 = Nothing
| otherwise = Just $ 0.25 * sqrt ((a+(b+c)) * (c-(a-b)) * (c+(a-b)) * (a+(b-c)))
where
[c, b, a] = sort [a',b',c']
However, I don't know that GHC can be trusted to calculate that exactly as written, so some additional care may be required.
Note that you may be better off accepting 0-area "triangles" for some purposes.

Create a method acting on different types in Haskell

I'm trying to use different data types in a list. e.g:
data Shape = Square Int
| Circle Int
| Rectangle Int Int
| Triangle Int Int Int
deriving (Show)
shapes = [Square 5, Circle 2, Rectangle 10 5]
showShapes :: [Shape] -> [Int]
showShapes [] = []
showShapes (s:xs) = getArea (s : xs)
However I'm struggling to create the method "getArea" as I need one for each different type. I don't know a way to do this using parameter pattern matching. Is there a way to do this or am I tackling this problem the wrong way?
Edit
How would you do it using an if statement and "typeOf" function
I tried changing Shape to this:
data Shape = Square Int
| Rectangle Int Int
| Triangle Int Int Int
deriving (Show, Typeable)
But I get a compile time error!
For your simple case, just use pattern matching in getArea, but you'll have to convert your values to Doubles since the area of a circle is never going to be an integer when you have an integer radius:
getArea :: Shape -> Double
getArea (Square l) = fromIntegral $ l * l
getArea (Circle r) = pi * fromIntegral r ^ 2
getArea (Rectangle l w) = fromIntegral $ l * w
-- assuming the constructor takes the 3 side lengths
getArea (Triangle a b c) = sqrt $ p * (p - a') * (p - b') * (p - c')
where
[a', b', c'] = map fromIntegral [a, b, c]
p = (a' + b' + c') / 2
Although I don't know what you want to do in showShapes. Usually the word show in Haskell means the same thing as toString in other languages, but you're trying to apply getArea inside it. Regardless, your pattern matching for showShapes is off, you need parentheses around s:xs or you'll get a syntax error, and you can't prepend a number on front of a list of Shapes as with getArea s : xs. Instead you might be wanting to calculate the area for each shape in a list? For that you can use map:
getAreas :: [Shape] -> [Double]
getAreas shapes = map getArea shapes
Note, that you don't need to store all figures in one datatype in this case. You can use existential quantification instead:
{-# LANGUAGE ExistentialQuantification #-}
data Square = Square Int
data Circle = Circle Int
data Rectangle = Rectangle Int Int
class HasArea a where
area :: a -> Double
instance HasArea Square where
area (Square n) = fromIntegral n * fromIntegral n
instance HasArea Circle where
area (Circle r) = pi * fromIntegral r ^ 2
instance HasArea Rectangle where
area (Rectangle n m) = fromIntegral n * fromIntegral m
data Shape = forall s. HasArea s => Shape s
shapes :: [Shape]
shapes = [Shape (Square 5), Shape (Circle 2), Shape (Rectangle 10 5)]
shapeArea :: Shape -> Double
shapeArea (Shape s) = area s
main = print $ map shapeArea shapes
You can read about existential quantification here: http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types
Existential quantification itself is weaker, than generalized algebraic datatypes. You can read about them here: http://en.wikibooks.org/wiki/Haskell/GADT

Resources