Monday, December 6, 2010

Euler in LISP, Oh my God!

I've spent the past several hours struggling to solve Project Euler problem 30 in LISP.  I want to die.

There were a few moments early in my code writing where I was enamored by how much was being done in so few lines, but the rest of the time was spent screaming profanity at my computer screen when I couldn't get even the simplest of things to work.

In the end, once I'd found the numbers I needed, I added them together with a calculator just to avoid writing another line of LISP.

 Since I know my code is a mess, I'm just going to include the code that calculates the sum of a number's digits to the P'th power.


(defun funSum (N P)
           (if (= N 0)
               0
               (+ (power (rem N 10) P) (funSum (values (floor N 10)) P))))

First, the functions in this program.

power: I had to write my own power function.  Returns N^P. See the code below.
(defun power (N P)
           (if (= P 1)
               N
               (* N (power N (- P 1)))))
rem: this returns the remainder of the first number divided by the second.  It's the equivalent of num1%num2

floor: this divides the first number by the second and rounds down to the nearest integer.

values: This isn't actually necessary for the code to work.  The idea is, the floor function actually returns two numbers, only one of which we need.  The values function suppresses the second number returned by floor.

funSum: This is the entire section of code you see above.  It calls itself inside itself (a programming technique known as recursion).  recursion is also used in the power function above.

Translation of funSum with N = 4151 and P = 5

if 4151 = 0, return 0

4151 != 0, so return (((4151%10)^5 + this whole process again with N = 4151/10 and P = 5)

the math in the last line:
4151%10 = 1
1^5 = 1
4151/10 = 415  <- note that we get rid of any decimal we get

Simplified, the last line is
return (1 + the whole process again with N = 415 and P = 5)

Then we do it all over again with N = 415 and P = 5 until we run out of digits.

That's recursion for you.  In LISP, it's everywhere.