sokras
sokras

Reputation: 629

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

Upvotes: 2

Views: 2240

Answers (1)

Sarah
Sarah

Reputation: 6695

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.

Upvotes: 7

Related Questions