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

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

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))

Creating list of values of the same typeclass but different types

I'm new to Haskell and trying to do something which I'm sure is easy but I'm not seeing the right way to do it.
What I want is a list of values of a particular typeclass, but different types of that typeclass. Eg:
class Shape a where
area :: a -> Double
numVertices :: a -> Integer
data Triangle = Triangle {...}
data Square = Square {...}
instance Shape Triangle where ...
instance Shape Square where ...
x = [Triangle (...), Square (...)]
I'm getting a compiler error because the list has different types. What's the right way to do what I'm trying to do here? The only thing I've been able to come up with is doing something like this:
data WrappedShape = WrappedShape {
getArea :: () -> Double
, getNumVertices :: () -> Integer
}
wrap s = WrappedShape {
getArea = \ () -> area s
, getNumVertices = \ () -> vertices s
}
x = [wrap (Triangle (...)), wrap (Square (...))]
This works, but it's heavy on boilerplate, since I have to effectively define Shape twice and with differently-named members. What's the standard way to do this sort of thing?
If you just need a few different shapes, you can enumerate each shape as a constructor, here is a example:
data SomeShapes = Triangle {...}
| Square {...}
instance Shape SomeShapes where
area (Triangle x) = ...
area (Square x) = ....
now you can put them in a list, because they are same type of SomeShapes
[Triangle {...}, Square {...}]
Your wrapped type is probably the best idea.
It can be improved by noting that, in a lazy language like Haskell, the type () -> T essentially works like the plain T. You probably want to delay computation and write stuff like let f = \ () -> 1+2 which does not perform addition until the function f is called with argument (). However, let f = 1+2 already does not perform addition until f is really needed by some other expression -- this is laziness.
So, we can simply use
data WrappedShape = WrappedShape {
getArea :: Double
, getNumVertices :: Integer
}
wrap s = WrappedShape {
getArea = area s
, getNumVertices = vertices s
}
x = [wrap (Triangle (...)), wrap (Square (...))]
and forget about passing () later on: when we will access a list element, the area/vertices will be computed (whatever we need). That is print (getArea (head x)) will compute the area of the triangle.
The \ () -> ... trick is indeed needed in eager languages, but in Haskell it is an anti-pattern. Roughly, in Haskell everything has a \ () -> ... on top, roughly speaking, s o there's no need to add another one.
These is another solution to your problem, which is called an "existential type". However, this sometimes turns into an anti-pattern as well, so I do not recommend to use it lightly.
It would work as follows
data WrappedShape = forall a. Shape a => WrappedShape a
x = [WrappedShape (Triangle ...), WrappedShape (Square ...)]
exampleUsage = case head x of WrappedShape s -> area s
This is more convenient when the type class has a lots of methods, since we do not have to write a lot of fields in the wrapped type.
The main downside of this technique is that it involves more complex type machinery, for no real gain. I mean a basic list [(Double, Integer)] has the same functionality of [WrappedShape] (list of existentials), so why bother with the latter?
Luke Palmer wrote about this anti-pattern. I do not agree with that post completely, but I think he does have some good points.
I do not have a clear-cut line where I would start using existentials over the basic approach, but these factors are what I would consider:
How many methods does the type class have?
Are there any methods of the type class where the type a (the one related to the class) appears not only as an argument? E.g. a method foo :: a -> (String, a)?

How to generate random triangle on a unit circle

I'm trying to find out the probability of the center of a unit circle falling inside a triangle. The vertexes of the triangle are randomly picked on the unit circle.
My idea is to pick a random float x in the range (-1.0, 1.0) and then randomly select up or down. This will get me one point (x, +/-sqrt(1 - x*x))
import Data.Random
main = do
x <- randomRIO (-1.0,1.0)
let y = (sample (randomElement [-1,1])) * sqrt(1-x*x)) -- I can't make this line work
So how do I select a random element from a [Int] ?
I don't speak Haskell, but to choose a point on a circle with even distribution, the variable you need to pick is the angle.
angle <- randomRIO(-pi, pi)
then
y = sin(angle)
x = cos(angle)
Pick 3 angles for your 3 dots and that gives you a random triangle.
As for testing if the center is in the triangle, I am fairly certain, though I have no demonstration so far, that you can go as follows:
Find the longest edge. The edge splits the circle in 2 parts
If the third vertex is in the smallest part, the center is not in the triangle
Else, it is
Edit, Demonstration
Let, ABC be a triangle in the circle of center D.
Let AB be the longest edge
Let C be on the largest half of the circle cut by AB
If D is not in ABC, then either AC or BC (for simplicity and since this is just naming convention, let assume AC) is the edge of the triangle that between AB and D
AC and AB being chords of the circle, the closest to the center is the longest
AC is longer than AB
How to apply this to angles only
From the previous demonstration, it quickly appears that if all 3 points are in the same half, the center is not in the triangle, otherwise it is.
The point is therefore to determine that the maximum distance between 2 points is pi.
Thanks to J. Abrahamson, we can compute the difference between all three points' angles, and sum the smaller two, return true if the sum is greater than pi.
The actual measurement of the distance between 2 points goes like this, as we need the absolute and most direct distance between the 2:
Compute the absolute distance diff = abs(theta1 - theta2)
If this is more than pi, use 2 * pi - diff
Look into the MonadRandom package, the uniform function will give you a random value from a list of values ([Int] in your case). I'm on my phone, but finding the package shouldn't be too tough. If you want to use a different distribution, look into random-fu.
An example of this using the MonadRandom package instead (cabal install MonadRandom):
import Control.Monad.Random
type R a = Rand StdGen a -- Just a type alias for less typing
type Point = (Double, Double)
type Triangle = (Point, Point, Point)
-- Monadic action
genAngle :: R Double
genAngle = getRandomR (-pi, pi)
-- Monadic action
genPoint :: R Point
genPoint = do
x <- genAngle
return (cos x, sin x)
-- Monadic action
genTriangle :: R Triangle
genTriangle = do
a <- genPoint
b <- genPoint
c <- genPoint
return (a, b, c)
-- Pure function
containsOrigin :: Triangle -> Bool
containsOrigin (a, b, c) = ??? -- You get to implement this (#njzk2 has given some pointers)
-- Monadic action
genTriangles :: R [Triangle]
genTriangles = do
tri <- genTriangle
rest <- genTriangles -- Recursion to get infinite list
return $ tri : rest
-- Monadic action
genTrianglesWithOrigin :: R [Triangle]
genTrianglesWithOrigin = do
triangles <- genTriangles
return $ filter containsOrigin triangles
main :: IO ()
main = do
triangles <- fmap (take 10) $ evalRandIO genTrianglesWithOrigin
mapM_ print triangles
If you want more reading on why MonadRandom is nicer than the base random package, I would recommend looking at this section of Learn You A Haskell. Basically, MonadRandom builds a nicer interface where not everything is in IO (which is dangerous, who knows what an IO function does) and provides some easy functions for generating random numbers, whereas the random package just provides the most barebones functionality possible. In fact, the Rand monad is nothing more than the State monad in disguise, it just keeps up with the state of your generator seed for you.

Resources