\$\begingroup\$
\$\endgroup\$
Objective:
- Create a function to sum a list of fractions (represented as pairs)
Rules
- Only Prelude functions allowed
Notes
- I was debating if I should create a
Fraction
data type. Is it worth "upgrading" from a simple pair? - Is the code easy to follow and well-structured? How are my function names?
- Is a simple
error
call a good way to inform the caller of incorrect arguments?
Code
sumOfFractions :: [(Integer, Integer)] -> (Integer, Integer)
sumOfFractions [] = error "empty list not allowed"
sumOfFractions fractions = reduce (numerator, lcd)
where
reduce (n, d) = (n `div` gcd_, d `div` gcd_)
numerator = sum . map (\(x, y) -> x * (lcd `div` y)) $ fractions
lcd = foldr1 lcm (map snd fractions)
gcd_ = gcd numerator lcd
1 Answer 1
\$\begingroup\$
\$\endgroup\$
There are two things that in my opinion would make your code easier to follow.
- The sum of zero numbers can be (and is usually) defined as zero, which is the identity element
0
of addition in the sense that $$ x = 0 + x = x + 0$$ holds for all x. - The sum of more than two numbers is perhaps best defined recursively, using the associativity property $$ x + y + z = (x+ y) + z = x + (y + z).$$
One way to use these properties in code is the following.
type MyFraction = (Integer, Integer)
sumOfFractions :: [MyFraction] -> MyFraction
sumOfFractions = foldl plus (0, 1)
plus :: MyFraction -> MyFraction -> MyFraction
plus (a, u) (b, v) = (c `div` x, w `div` x)
where c = a*v + b*u
w = u*v
x = gcd c w
It should be a fun exercise to define a datatype so that (+)
, and by extension sum
works on them. Type t: (+)
into an interpreter and go from there!
To answer your last two questions:
- Your function names are fine. Perhaps
reduce
should besimplify
. - There's no need for an exception here, but I believe
error
is fine for this purpose in general.
answered Apr 18, 2021 at 22:01
Explore related questions
See similar questions with these tags.
lang-hs