HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Filtering triangles

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
trianglesfilteringstackoverflow

Problem

I'm playing with Haskell's list comprehensions, tuples, and foldr.

The exercise I've given myself is to find all triangles with a perimeter of length 26 in the set of triangles whose edges range from 1 to 10 in length.

main = do
  print triangles

triangles = [(a,b,c) | a <- [1..10], b <- [1..10], c <- [1..10], hasPerimeterOf 26 (a,b,c)]

-- Determines whether a triangle has a perimeter of targetPerimeter
hasPerimeterOf targetPerimeter triangle = targetPerimeter == perimeter triangle

-- Calculates the perimeter of a triangle
perimeter triangle = foldr (+) 0 (toList(triangle))

-- Converts a tuple of three to a list
toList (a,b,c) = a : b : c : []


Is there a nicer way to convert a homogenous tuple to a list?

Generally, are there ways to simplify this code?

Solution

The sum of length of any two sides of a triangle must be bigger then the length of the third side. Therefore there is no need to calculate hasPerimeterOf for all combinations of a, b and c. You can simplify it by adding another filter:

triangles = [(a,b,c) | a <- [1..10], b <- [1..10], c <- [1..10], c < a + b, hasPerimeterOf 26 (a,b,c)]



Generally, are there ways to simplify this code?

I would simply use pattern matching on the tuple in perimeter like this:

perimeter (a,b,c) = a + b + c


hasPerimeterOf seems redundant here, anyway. Why not simply compare the perimeter with the desired value? It will be very readable and concise that way. The final code:

main = do
   print triangles

triangles = [(a,b,c) | a <- [1..10], b <- [1..10], c <- [1..10], trianglePerimeter (a,b,c) == 26]

trianglePerimeter (a,b,c) = a + b + c


Note that I replaced the comment with a more meaningful function name.

EDIT:

As 200_success rightfully pointed out in the comment, the c < a + b filter leads to awkward results, because it removes some duplicate triangles, leaving other duplicates untouched. In my opinion, if triangles (1,2,4) and (2,4,1) are the same, then the final result should contain only one triangle for each unique set of sides. Otherwise, the mentioned filter has to be removed.

Code Snippets

triangles = [(a,b,c) | a <- [1..10], b <- [1..10], c <- [1..10], c < a + b, hasPerimeterOf 26 (a,b,c)]
perimeter (a,b,c) = a + b + c
main = do
   print triangles

triangles = [(a,b,c) | a <- [1..10], b <- [1..10], c <- [1..10], trianglePerimeter (a,b,c) == 26]

trianglePerimeter (a,b,c) = a + b + c

Context

StackExchange Code Review Q#123375, answer score: 4

Revisions (0)

No revisions yet.