February 4, 2008
@ 06:31 AM

Here.

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

This problem is pretty straightforward, but to get started, I needed to take the first step(s):

  1. Got the latest F# installed.
  2. Created an F# project.
  3. Created a C# xUnit.net test project (another thing I picked up at Code Camp.)

I tried to create an xUnit.net project in F#, but ran into some problem (can't remember what) and decided I was better off focusing my F# mana on the Euler problems than learning xUnit.net in F# and using F#. Doing the unit tests in C# was easy.

So, as a TDD'er, I broke the problem down into chunks I could write tests for:

  1. I needed a way to identify if numbers were multiples of each other:
        public class Problem_001_Tests
        {
            [Fact] private void Numbers_are_multiples_of_themselves()
            {
                Assert.True(Problem001.IsMultiple(3, 3));
            }
            [Fact] private void Any_X_Times_Y_Is_A_Multiple_of_X()
            {
                Assert.True(Problem001.IsMultiple(3, 3*23));
                Assert.True(Problem001.IsMultiple(23, 3 * 23));
            }
        }
  2. I implemented this in F#:
    #light

    namespace Euler

        module Problem001

        let IsMultiple n x = 
            x % n = 0

     

  3. Comfortable that basic math works, I wanted to try one of the features I really find appealing about F#: sequences:
            [Fact] private void AllMultiplesOf3Or5Under1000ShouldInclude525()
            {
                Assert.True(Problem001.AllMultiplesOfThreeOrFiveLessThan(1000)
                    .Contains(525));
            }
            [Fact] private void AllMultiplesOf3Or5Under1000ShouldNotInclude200()
            {
                Assert.False(Problem001.AllMultiplesOfThreeOrFiveLessThan(200)
                    .Contains(200));
            }
     
    ...
        let AllMultiplesOfThreeOrFiveLessThan n = 
            seq { 
                for x in 1..n - 1 do
                    if IsMultiple 3 x then yield x
                    else if IsMultiple 5 x then yield x 
            }

    Sequences seem a lot like IEnumerable<T> functions in C#, which I have been using a lot of.

  4. And finally, the answer:

     

            [Fact] private void FunctionalAnswerSameAsImperativeAnswer()
            {
                int accumulator = 0;
                foreach (int x in Problem001.AllMultiplesOfThreeOrFiveLessThan(1000))
                    accumulator += x;

                int answer = Problem001.SumOfAllMultiplesOfThreeOrFiveLessThanOneThousand();
                Assert.Equal(accumulator, answer);
                Console.WriteLine("The answer is: {0}", answer);
            }
            [Fact] private void TheAnswerIs233168()
            {
                Assert.Equal(233168, Problem001.SumOfAllMultiplesOfThreeOrFiveLessThanOneThousand());
            }

    ...

        let SumOfAllMultiplesOfThreeOrFiveLessThanOneThousand () =
            let range = AllMultiplesOfThreeOrFiveLessThan(1000)
            Seq.fold (+) 0 range

I like the way you can use the "+" operator as a first class function.

So that's it. Pretty dumb. Once I'd plugged in the answer to Project Euler, I took a look around the forums. My answer is dumb and verbose compared to some of the answers in the forums. Which brings me to an interesting conundrum:

In C#, and production development in general - I consider it poor style to write code that's really "mathy" - Single letter variable names, lots of terse iteration and use of abbreviated keywords. I like to have long descriptive method names and have the "nameable" parts of an algorithm broken out into named methods.

F# takes me the other way. It appeals to the side of me that likes elimination of waste. The side that throws boxes and packaging away as soon as I get something - preferably at the store. Once you understand the above problem, it's really just a one liner (see Project Euler forums.)

The C# (maybe I should say DDD) solution shows the work: You can literally see the steps taken to get the answer - not the program's steps, but the _programmer's_ steps. I think this is very desirable in a program, and will have to make sure I don't lose this in the elegance and sleekness of F#.


 
Categories: