I am learning Haskell and as exercise I am doing Project Euler Problems. In this case PE1.
-- Sum any given finite Airthmetic Progression
sumAP :: Integer -> Integer -> Integer -> Integer
sumAP first limit step = do
let last = limit - (limit `rem` step)
let terms = (last - first) `quot` step + 1
let avg = first + last
terms * avg `quot` 2
Now, off the bat I am shadowing the last function. How could I rename this variable along with first?
Is there any way I can improve readability? Any edge case or fail case I haven't covered? Any performance fail?
2 Answers 2
My first comment would be to comment your code.
You need documentation so I know what your function is meant to do. "Sum any given finite Arithmetic Progression" would suffice if you passed in an ArithmeticProgression
, but instead you pass in some bounds. Writing an arithmetic progression type would be simple and might even help a little, but you still need to document that.
I don't know what algorithm you're trying to use. You've evidently taken some maths for sums of arithmetic progressions and applied it to the problem, but there's no way for me to verify that the maths is correct or that the code implements it correctly without at least rudimentary explanation of what you did. I could reimplement it myself, but code should be verifiable much more easily than that.
-
\$\begingroup\$ Added comments, hope it became more readable. \$\endgroup\$Fabián Heredia Montiel– Fabián Heredia Montiel2015年06月20日 19:52:45 +00:00Commented Jun 20, 2015 at 19:52
-
\$\begingroup\$ @FabiánH.jr. You're not meant to change any code in the question that would invalidate any answers, so the edit is invalid. Feel free to add it as text outside of the code, though. \$\endgroup\$Veedrac– Veedrac2015年06月20日 20:00:15 +00:00Commented Jun 20, 2015 at 20:00
-
\$\begingroup\$ Sorry about that, my bad; I separated the code into the original version and an updated version from feedback. Is that better or should I take another approach? \$\endgroup\$Fabián Heredia Montiel– Fabián Heredia Montiel2015年06月20日 20:04:45 +00:00Commented Jun 20, 2015 at 20:04
-
\$\begingroup\$ Supposedly appending code is also disallowed. See meta.codereview.stackexchange.com/questions/1763/…. \$\endgroup\$Veedrac– Veedrac2015年06月20日 20:35:22 +00:00Commented Jun 20, 2015 at 20:35
-
\$\begingroup\$ Oh, interesting. I will remove the edits then. \$\endgroup\$Fabián Heredia Montiel– Fabián Heredia Montiel2015年06月20日 21:01:51 +00:00Commented Jun 20, 2015 at 21:01
Int
faster than Integer
. If you have acceptable limitations you should use Int.
"Integer" is an arbitrary precision type: it will hold any number no matter how big, up to the limit of your machine's memory.... This means you never have arithmetic overflows. On the other hand it also means your arithmetic is relatively slow. Lisp users may recognise the "bignum" type here.
"Int" is the more common 32 or 64 bit integer. Implementations vary, although it is guaranteed to be at least 30 bits.
Source: The Haskell Wikibook. Also, you may find the Numbers section of A Gentle Introduction to Haskell useful.
Copy-paste from Haskell Int and Integer
sumAP 3 11 2
gives26
. So I believe that your function is wrong. \$\endgroup\$rem
step to last puts it back in the same offset from 0 as first. \$\endgroup\$