Haskell Task Instance - haskell

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

Related

Haskell Translation Task

I'm new to programming, and I'm having trouble solving a task.
I have to use the function. In that case I have to implement it on a triangle.
I've tried different things but I'm just getting errors and that's why I'd like to ask for help.
data Triangle = Triangle {
tP1 :: Point,
tP2 :: Point,
tP3 :: Point}
deriving (Show)
First, points and vectors are two separate concepts, and should probably be distinct types, not just two different aliases for a 2-tuple.
data Point = Pt Float Float
data Vector = V Float Float
Second, your type class seems to capture the idea of translating collections of points using the same vector. The return type should then be the same as the first argument type, not hard-coded to Point.
class Polygon p where
translatePol :: p -> VectorD -> p
Now you can start simple, and define a Polygon instance for Point. (Think of a point as a degenerate polygon.)
instance Polygon Point where
translatePol (Pt x y) (Mvector v1 v2) = Pt (x + v1) (y + v2)
This can be used to define the instance for Triangle more simply.
instance Polygon Triangle where
translatePol (MTriangle p1 p2 p3) v = MTriangle (t p1) (t p2) (t p3)
where t p = translatePol p v

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 add an element to a list of a data type in Haskell

I have defined two data types: Point and Curve. Point has two doubles for its coordinates and a Curve has a starting Point and a list of Points representing the rest of the Curve. I need to make a function that creates this Curve given a starting Point and a list of Points but I can't quite understand how am I supposed to add an element to the list of Points inside the Curve.
Here is my code:
data Point = Point Double Double deriving (Eq, Show)
point :: (Double, Double) -> Point
point (x, y) = Point x y
data Curve = Curve Point [Point] deriving (Eq, Show)
curve :: Point -> [Point] -> Curve
curve x [] = Curve x []
curve x [y] = Curve x [y]
curve x (y:ys) = curve x (y:ys)
I am pretty sure my recursion in the end is wrong. So could you give me maybe some guidelines on how to add a point in the list?
thanks
myCurve = Curve (Point 2 2) [Point 3 3, Point 4 4, Point 5 5]
Wait, what, you say? Indeed, Curve is already that function you want. It is both a type constructor (the left-hand-side in the data definition) and a value constructor (the right hand side.)
If you probe Curve with ghci, you will find...
Prelude> :t Curve
Curve :: Point -> [Point] -> Curve
The same goes for Point. In other words, the entirety of your code looks like this:
data Point = Point Double Double deriving (Eq, Show)
data Curve = Point [Point] deriving (Eq, Show)
EDIT: An ultra-small primer on value constructors.
When you create a new datatype, you automatically create a value constructor, which is a function that creates a value of the new type. It's not entirely clear in your example because the type and value constructors have the same name, which is permissible in Haskell because one lives in the type level and the other in the value level. Let's try and make it a bit more obvious:
data MyIntType = MakeIntType Int
Now, MakeIntType is a function that takes one argument, an Int, and creates a value of type MyIntType. Let's check that in ghci:
Prelude> :t MakeIntType
MakeIntType :: Int -> MyIntType
Now, we could write an identical function, like you're proposing:
makeIntType :: Int -> MyIntType
makeIntType x = MakeIntType x
or, dropping the explicit points (arguments):
makeIntType = MakeIntType
Both equation shows that we've duplicated work. There is no functional difference between makeIntType and MakeIntType. They are completely equivalent, and since you will always get the value constructor function "for free," makeIntType is a completely superfluous alias for something that's already there.
I hope that clears things up a bit.
Edit 2: Creating a new modified Curve based on an existing one
addPointToStartOfCurve p (Curve p' ps) = Curve p (p':ps)
Here, we create a new Curve from an existing one by pushing the first element of the existing Curve onto the list of points and adding a new starting point. Another variant would add a point to the end of an existing Curve.
addPointToEndOfCurve p (Curve p' ps) = Curve p' (ps ++ [p])
Note that because of immutability, the original curves aren't altered, we're just producing new values.

Creating figures in 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.

What is wrong with this class/instance?

I have this:
data Vector3 t = Vector3 { ax, ay, az :: t }
data Point3 t = Point3 { x, y, z :: t }
data Ray3 t = Ray3 { ori :: Point3 t, dir :: Vector3 t }
data Sphere t = Sphere { center :: Point3 t, radius :: t }
I want a Shape type class, so I did this:
class Shape s where
distance :: s -> Ray3 t -> t
distance takes a shape and a ray and computes the distance to the shape along the given ray. When I try to create an instance, it doesn't work. This is what I have so far:
instance Shape (Sphere t) where
distance (Sphere center radius) ray = -- some value of type t --
How do I create an instance of Shape? I've tried everything I can think of, and I'm getting all kind of errors.
The problem is that the type variable t in Sphere t is not the same as the one in the type signature of distance. Your current types are saying that if I have a Sphere t1, I can check it against a Ray3 t2. However, you probably want these to be the same type. To solve this, I would change the Shape class to
class Shape s where
distance :: s t -> Ray3 t -> t
Now the dependency on t is explicit, so if you write your instance as
instance Shape Sphere where
distance (Sphere center radius) ray = ...
the types should line up nicely, although you'll probably need to add in some numeric constraints on t to do any useful calculations.

Resources