Creating figures in Haskell - haskell

Im trying to create datatype "Figure" in Haskell, this datatype should have multiple values:
Square (with parameter length)
Triangle (with parameter length)
Circle (with parameter radius)
Every figure should have a color as well (let's say black and white), this is how my code currently looks like but this doesn't work.
Can anyone help me?
class Figure_ a where
perimeter :: a -> Double
area :: a -> Double
data Figure = forall a. Figure_ a => Figure a
type Radius = Double
type Side = Double
type Color = String
data Circle = Circle Radius
data Triangle = Triangle Side
data Square = Square Side
instance Figure_ Circle where
perimeter (Circle r) = 2 * pi * r
area (Circle r) = pi * r * r
instance Figure_ Triangle where
perimeter (Triangle x y) = 2*(x + y)
area (Triangle x y) = x * y
instance Figure_ Square where
perimeter (Square s) = 4*s
area (Square s) = s*s
instance Figure_ Figure where
perimeter (Figure shape) = perimeter shape

For forall use:
{-# LANGUAGE ExistentialQuantification #-}
Also, your triangle is accepting two parameters, so it should be like this:
data Triangle = Triangle Side Side
But looking at the formula of your Triangle, I think you seem to be confusing it with Rectangle. Also, indentation of your code doesn't seem to be correct. Your code should look like this:
class Figure_ a where
perimeter :: a -> Double
area :: a -> Double
The same indentation rule should also be followed when you create instance of that typeclass.

Im trying to create datatype "Figure" in Haskell, this datatype should have multiple values:
Square (with parameter length)
...
Circle (with parameter radius)
I'm leaving out the triangle to avoid thinking about geometry. Anyway, the questions sounds like you might want the following:
data Figure = Square Double | ... | Circle Double
And then you can define functions like:
area :: Figure -> Double
area (Square side) = side * side
area ... = ...
area (Circle radius) = pi * radius * radius
If you only need one datatype, you don't need classes in Haskell. Haskell classes are for having more than one datatype when they all support a common interface.
There is one reason to prefer your construction with class and forall over the otherwise simpler version with just data: In your version, it is easier to add another kind of figure that was not planned for. If you feel you need this, you might want to read about the existential typeclass antipattern. But if you're just trying to represent figures in Haskell at all, I would certainly start with a simple datatype.

Related

Haskell Task Instance

I saw this exercise in a book and I am trying to do it but can't get any further.
What I'm trying to do is implement, for the data type, a function
area_t :: p -> Double
that returns the area of a general triangle.
The data type Triangle defines the function "area_t".
My current code:
data Triangle = MTriangle {
tP1 :: Point,
tP2 :: Point,
tP3 :: Point}
class Polygon p where
area_t :: p -> Float
instance Polygon Point where
instance Polygon Triangle where
area_t
Error :
Couldn't match expected type ‘Float’
with actual type ‘Point -> Point -> Float -> Point’
• The equation(s) for ‘area_t’ have three arguments,
but its type ‘Point -> Float’ has only one
The area of a point is 0, so the instance for Polygon Point (if you consider points to be polygons at all), should be:
instance Polygon Point where
area_t _ = 0
Then the code you wrote for the area of a triangle seems alright, but there's two problems:
You are pattern matching on three separate points instead of a triangle
You are producing a point instead of a plain float
A working instance might look like this:
instance Polygon Triangle where
area_t (MTriangle (MPoint x1 y1) (MPoint x2 y2) (MPoint x3 y3))
= ((x2-x1)*(y3-y1) - (x3-x1)*(y2-y1))/2

Algebraic Types - Haskell

I am working around with algebraic types in Haskell, doing some exercises from a worksheet. I got the following exercises:
Define an algebraic type Point for representing (the coordinates of) points in twodimensional space.
My code for this exercise:
data Point = Point Float Float
deriving (Show)
Using Point, define a modified version PositionedShape of the Shape data type which
includes the centre point of a shape, in addition to its dimensions.
Shape data previously defined:
data Shape = Circle Float |
Rectangle Float Float
deriving (Show)
My code for this exercise:
data PositionedShape = PositionedShape Shape Point
deriving (Show)
Now my question comes in this one:
Define a function:
haskell move :: PositionedShape -> Float -> Float -> PositionedShape
which moves a shape by the given x and y distances
My implementation for this was the following:
move :: PositionedShape -> Float -> Float -> PositionedShape
move (Shape (Point x y)) newX newY = Shape (Point newX newY)
This is returning me this error:
Week8.hs:103:7: error: Not in scope: data constructor ‘Shape’
Failed, modules loaded: none.
Can someone please explain me why this error and how can I solve it? I am getting a bit confused with algebraic types, I tried a lot of things but it just seems I can't get a solution.
You need to pattern match on data constructors (like Circle and Rectangle), not on type constructors as you're trying to do now (like Shape). For PositionedShape, they happen to have the same name, although you completely forgot the match on this one (and in fact, you don't need to care about the inner Shape at all except to copy it through). Also, move is meant to move the shape by the given distances, not to move it to a new given position;.
You need to use the PositionedShape constructor to break apart a PositionedShape You have used the Shape constructor instead.
Try starting with:
move (PositionedShape shape (Point old_x old_y)) [...]
How about
move (PointedShape s (Point x y)) dx dy = PointedShape s (Point (x+dx) (y+dy))

How to make function useable only for a certain data constructor of an ADT?

I'm currently playing around with ADTs in Haskell and try to build an ADT Figure:
data Figure = Rect { x :: Integer, y :: Integer, width :: Integer, height :: Integer}
| Circle { x :: Integer, y :: Integer, radius :: Integer}
| CombiFigure Figure Figure
deriving (Eq, Show, Read)
Now I came across the question how to implement a function that should not accept every Figure, but e.g. only a Circle.
Do I already have a bad design? Or is there some best-practice how to do this?
As example, think about a diameter function. All that came to my mind (I'm a complete beginner in Haskell) are the following two options, using undefined or Maybe:
1:
diameter :: Figure -> Integer
diameter (Circle _ _ r) = 2 * r
diameter _ = undefined
2:
diameter :: Figure -> Maybe Integer
diameter (Circle _ _ r) = Just (2 * r)
diameter _ = Nothing
Are there more preferable ways on how to accomplish that?
Thanks!
You are correct that there is something not right here. The best way of thinking about it would be to start at the function diameter and decide what it's type should ideally be. You would likely come up with
diameter :: Circle -> Integer
diameter (Circle _ _ r) = 2 * r
because diameters are only defined for circles.
This means that you will have to augment your data structure by splitting out Circle (and Rect too):
data Figure = RectFigure Rect
| CircleFigure Circle
| CombiFigure Figure Figure
deriving (Eq, Show, Read)
data Rect = Rect { rectX :: Integer, rectY :: Integer, rectWidth :: Integer, height :: Integer}
deriving (Eq, Show, Read)
data Circle = Circle { circleX :: Integer, circleY :: Integer, circleRadius :: Integer}
deriving (Eq, Show, Read)
which is nice because it is now more flexible: you can write functions that don't care what Figure they are applied to, and you can write functions that are defined on specific Figures.
Now, if we are in a higher-up function and have a reference to a Figure and we want to compute its diameter if it's a CircleFigure, then you can use pattern matching to do this.
Note: using undefined or exceptions (in pure code) is likely a code smell. It could probably be solved by rethinking your types. If you have to indicate failure, then use Maybe/Either.
Your type definition by itself (i.e data Figure = ...) is introducing partial functions. e.g. even though width is of type width :: Figure -> Integer it can only work on Rect values:
\> width $ Rect 1 2 3 4
3
\> width $ Circle 1 2 3
*** Exception: No match in record selector width
so, you already have defined functions which can work on one figure but not another (similar to diameter function in the question).
That said, a 3rd solution would be to define Circle, Rectangle etc, as separate types; then, define a Figure type class which defines the common interface of these types.
class Figure a where
area, perimeter :: a -> Double
instance Figure Circle where
area = ...
perimeter = ...
Additionally each type may have their own exclusive functions. Or, you may add more interfaces, (i.e. type classes) which cover some but not all the figure types.
An advantage of type classes is that they are easier to extend; e.g. if one wants to add, say, a Triangle type later on, he can opt-in any type class which applies to a triangle, and define an instance only for those type classes.
Whereas in the data Figure = ... approach, you need to find every function which can take a Figure as argument and make sure it will handle a Triangle as well. If you are shipping a library then you do not have access to all these functions.
>> for the reference, there was a similar recent discussion of data declaration vs type classes on haskell cafe mailing list.

typeclasses, overloading and instance declaration

Having this:
data Rectangle = Rectangle Height Width
data Circle = Circle Radius
class Shape a where
area :: a -> Float
perimeter :: a -> Float
instance Shape Rectangle where
area (Rectangle h w) = h * w
perimeter (Rectangle h w) = 2*h+w*2
instance Shape Circle where
area (Circle r) = pi * r**2
perimeter (Circle r) = 2*pi*r
volumenPrism base height = (area base) * height
surfacePrism shape h = (area shape) * 2 + perimeter shape * h
Why cant I write this? a is a type so why doesn't this work?
instance (Shape a) => Eq a where
x==y = area x == area y
Obviously doing like this:
instance Eq Circle where
x==y = area x == area y
first for Circle and then for Rectangle works..but it seems not the right way.
What is it I don't get in all this?
Ty
The fundamental problem is that the type class instance resolution machinery doesn't backtrack. So if you write instance Shape a => Eq a, then whenever the compiler wants to find an Eq instance, the compiler will try to use this instance and for most types it won't work out because they aren't instances of Shape.
If you still really want to do this, you can add
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
at the top of your source file.
You can also work round some of the problems described above by also adding OverlappingInstances to the set of LANGUAGE pragmas, but you will still have a global instance for Eq that will cause significant confusion elsewhere in your program.
It's much better to just enumerate the instances you really need, even if it seems ugly. You can keep the boilerplate to a minimum with a helper function, e.g.
x `areaEq` y = area x == area y
and then
instance Eq Circle where
(==) = areaEq
etc.

haskell polymorphism and lists

Suppose I have the following:
class Shape a where
draw a :: a -> IO ()
data Rectangle = Rectangle Int Int
instance Shape Rectangle where
draw (Rectangle length width) = ...
data Circle = Circle Int Int
instance Shape Circle where
draw (Circle center radius) = ...
Is there any way for me to define a list of shapes, traverse over the list, and call the draw function on each shape? The following code won't compile because the list elements aren't all the same type:
shapes = [(Circle 5 10), (Circle 20, 30), (Rectangle 10 15)]
I know I'm thinking in an OO way and trying to apply it to Haskell, and that might not be the best approach. What would be the best Haskell approach for programs that need to deal with collections of different types of objects?
If you really do need to do this, then use an existential:
{-# LANGUAGE GADTs #-}
class IsShape a where
draw :: a -> IO ()
data Rectangle = Rectangle Int Int
instance IsShape Rectangle where
draw (Rectangle length width) = ...
data Circle = Circle Int Int
instance IsShape Circle where
draw (Circle center radius) = ...
data Shape where
Shape :: IsShape a => a -> Shape
shapes = [Shape (Circle 5 10), Shape (Circle 20 30), Shape (Rectangle 10 15)]
(I renamed your class as there would be a name clash with the datatype otherwise, and having the naming this way round seems more natural).
The advantage of this solution over the other answer involving a single datatype with different constructors is that it is open; you can define new instances of IsShape wherever you like. The advantage of the other answer is that it's more "functional", and also that the closedness may in some cases be an advantage as it means that clients know exactly what to expect.
Consider using a single type instead of separate types and a typeclass.
data Shape = Rectangle Int Int
| Circle Int Int
draw (Rectangle length width) = ...
draw (Circle center radius) = ...
shapes = [Circle 5 10, Circle 20 30, Rectangle 10 15]
One way to do it would be with vtables:
data Shape = Shape {
draw :: IO (),
etc :: ...
}
rectangle :: Int -> Int -> Shape
rectangle len width = Shape {
draw = ...,
etc = ...
}
circle :: Int -> Int -> Shape
circle center radius = Shape {
draw = ...,
etc = ...
}
As Ganesh said, you could indeed use GADTs to have more type safety. But if you don't want (or need) to, here's my take on this:
As you already know, all elements of a list need to be of the same type. It isn't very useful to have a list of elements of different types, because then your throwing away your type information.
In this case however, since you want throw away type information (you're just interested in the drawable part of the value), you would suggest to change the type of your values to something that is just drawable.
type Drawable = IO ()
shapes :: [Drawable]
shapes = [draw (Circle 5 10), draw (Circle 20 30), draw (Rectangle 10 15)]
Presumably, your actual Drawable will be something more interesting than just IO () (maybe something like: MaxWidth -> IO ()).
And also, due to lazy evaluation, the actual value won't be drawn until you force the list with something like sequence_. So you don't have to worry about side effects (but you probably already saw that from the type of shapes).
Just to be complete (and incorporate my comment into this answer): This is a more general implementation, useful if Shape has more functions:
type MaxWith = Int
class Shape a where
draw :: a -> MaxWidth -> IO ()
size :: a -> Int
type ShapeResult = (MaxWidth -> IO (), Int)
shape :: (Shape a) => a -> ShapeResult
shape x = (draw x, size x)
shapes :: [ShapeResult]
shapes = [shape (Circle 5 10), shape (Circle 20 30), shape (Rectangle 10 15)]
Here, the shape function transforms a Shape a value into a ShapeResult value, by simply calling all the functions in the Shape class. Due to laziness, none of the values are actually computed until you need them.
To be honest, I don't think I would actually use a construct like this. I would either use the Drawable-method from above, or if a more general solution is needed, use GADTs. That being said, this is a fun exercise.
How to deal with a heterogeneous list of shapes in Haskell — Abstract polymorphism with type classes:
http://pastebin.com/hL9ME7qP via #pastebin
CODE:
{-# LANGUAGE GADTs #-}
class Shape s where
area :: s -> Double
perimeter :: s -> Double
data Rectangle = Rectangle {
width :: Double,
height :: Double
} deriving Show
instance Shape Rectangle where
area rectangle = (width rectangle) * (height rectangle)
perimeter rectangle = 2 * ((width rectangle) + (height rectangle))
data Circle = Circle {
radius :: Double
} deriving Show
instance Shape Circle where
area circle = pi * (radius circle) * (radius circle)
perimeter circle = 2.0 * pi * (radius circle)
r=Rectangle 10.0 3.0
c=Circle 10.0
list=[WrapShape r,WrapShape c]
data ShapeWrapper where
WrapShape :: Shape s => s -> ShapeWrapper
getArea :: ShapeWrapper -> Double
getArea (WrapShape s) = area s
getPerimeter :: ShapeWrapper -> Double
getPerimeter (WrapShape s) = perimeter s
areas = map getArea list
perimeters = map getPerimeter list
A variant of Ganesh's solution using the existential quantification syntax instead.
{-# LANGUAGE ExistentialQuantification #-}
class IsShape a where
draw :: a -> String
data Rectangle = Rectangle Int Int
instance IsShape Rectangle where
draw (Rectangle length width) = ""
data Circle = Circle Int Int
instance IsShape Circle where
draw (Circle center radius) = ""
data Shape = forall a. (IsShape a) => Shape a
shapes = [Shape (Circle 5 10), Shape (Circle 20 30), Shape (Rectangle 10 15)]

Resources