Idiomatic list construction

147 views Asked by At

I'm very new to Haskell and functional programming in general, so I don't really know how to make this code idiomatic:

type Coord = Double
data Point = Point Coord Coord Coord deriving Show

type Polyline = [Point]

-- Add a point to a polyline
addPoint :: Polyline -> Point -> Polyline
addPoint line p = p:line

line :: Polyline
line = []

constructLine :: Polyline -> Polyline
constructLine line =
    let 
        p1 = Point 2 4 87
        p2 = Point 3 7 2
        p3 = Point 23 4 8
    in addPoint (addPoint (addPoint line p1) p2) p3

main :: IO() 
main = do
    putStrLn ( show (constructLine line))

My problem is in the constructLine function. If I want to add a lot of points the nested addPoint functions are going to be a problem. How can I factor this? And do you see other things that could be improved?

2

There are 2 answers

0
JP Moresmau On BEST ANSWER

The multiple call to addPoints could be replaced by a fold. As suggested in a comment, reversing your addPoint function would make things easier:

addPoint' :: Point -> Polyline ->  Polyline
addPoint' p line = p:line

So then your constructLine function could build a temporary list of the points to add add use a fold:

constructLine :: Polyline -> Polyline
constructLine line =
    let
        p1 = Point 2 4 87
        p2 = Point 3 7 2
        p3 = Point 23 4 8
    in foldr addPoint' line [p3,p2,p1]

This does not break the encapsulation (you can replace your implementation of Polyline by something else than a list of Point) and uses the new points in the order they're going to end up at (p3 in front of p2, etc.)

2
Luis Casillas On

Your constructLine example just strikes me as a long-winded version of this:

constructLine :: Polyline -> Polyline
constructLine line = [Point 23 4 8, Point 3 7 2, Point 2 4 87] ++ line

I don't know if you've come across these yet, but just to be sure:

  • [Point 23 4 8, Point 3 7 2, Point 2 4 87] is just a list literal.
  • ++ is the function to append lists.

Generally, to add multiple elements to a list, what you do is you have a list of the elements that you wish to add, and append that list together with the original list.

This pattern continues. If we notice that line is a constant defined to [], then your whole program really is just a long-winded version of this:

type Coord = Double
data Point = Point Coord Coord Coord deriving Show

main :: IO () 
main = putStrLn (show points)
     where points = [Point 23 4 8, Point 3 7 2, Point 2 4 87]

Basically, if the points' values are known at compilation time, you can just write the list, there's no need to go through all this indirection.