Today we've reached a milestone. 10 Project Euler problems solved, using Functional C# 3.0. To celebrate, I've put the code for all the solutions up on Microsoft's Code Gallery.
You can find them at http://code.msdn.Microsoft.com/projecteuler. I intend to keep this up to date, as I add new solutions.
Before going public, I wanted to spruce up my code a little. It's all held in a Console App. As I was adding new solutions to my project, I'd been creating them as classes, each with their own public static void Main() method, and changing the Startup object in Visual Studio to point to the one I wanted to run. Not very elegant.
What I wanted was a menu that would list all the problems numbers and their titles, and allow the user to pick the one to solve. Being lazy (a great virtue in a programmer!), I didn't want to have to update this menu each time I added a new solution to the project. Let the program find out for itself what solutions exist, I thought.
But how to do that? Enter, Attributes. Attributes are a way of decorating code with additional information. You'll have used an attribute when ever you've marked a class as being Serializable: they are the things that live inside square brackets just before the thing you're decorating. They are often used in combination with Reflection. This is a powerful area of the .Net Base Class libraries which allow you to inspect your code whilst it is running, create classes on the fly, call methods by name, and all kinds of exciting (and just a little scary) things like that.
I decided to create an Attribute to show my program that a particular class is a Project Euler problem solver. The attribute will hold the problem number, and its title.
You define it like this:
public class EulerProblemAttribute : Attribute { public EulerProblemAttribute(int problemNumber) { ProblemNumber = problemNumber; } public int ProblemNumber { get; set; } public string Title { get; set; } }
Simple, isn't it. It's like any other class, the key point being that it inherits from Attribute. This is how you use it to decorate a class:
[EulerProblem(7, Title="Find the 10001st prime.")] public class Problem7 { public void Solve() { ...
The next step is to write some code that will find all the classes in the project that are marked with this attribute. This provides a nice opportunity to demonstrate a very practical use of LINQ: you could call it LINQ-to-Reflection.
What I've done is to create a class called EulerProblemSolverMetadata which will hold the information about each solver. The Reflection APIs provide classes that represent the various aspects of code in assemblies. For instance Type holds information about types - classes, structs, etc. MethodInfo holds information about a Method - and allows that method to be invoked dynamically on an object of the appropriate type. So in my EulerProblemSolverMetadata I've put a property called Class which holds the type of the solver, and a property called Method which holds a MethodInfo object representing the "Solve" method which I've decided each solver must have.
Here's the LINQ query that will populate my metadata class for me:
var problemSolvers = from type in Assembly.GetExecutingAssembly().GetTypes() // filter out types that are not decorated with the EulerProblemAttribute where Attribute.IsDefined(type, typeof(EulerProblemAttribute)) // ensure that the type has a parameterless public Solve method let method = type.GetMethod("Solve", new Type[] { }) where method != null // get hold of the attribute, so that we can get the metadata from it let attribute = Attribute.GetCustomAttribute(type, typeof(EulerProblemAttribute)) as EulerProblemAttribute // sort the problems into ascending order orderby attribute.ProblemNumber ascending select new EulerProblemSolverMetadata { Class = type, Number = attribute.ProblemNumber, Title = attribute.Title, Method = method };
Now that we've discovered what Solvers are available, we can present the list to the user and ask them to choose one. Once they've made a choice we need to use the metadata to run the appropriate piece of code. To do that we use the Activator class to create an instance of the appropriate Solver type. Then we invoke it's Solve method:
object instance = Activator.CreateInstance(chosenSolver.Class); chosenSolver.Method.Invoke(instance, new object[] { });
Easy, when you know how.
You can see the full code in the project on the MSDN code gallery.
Next time: LINQ-to-Console!
2 comments:
Talking about functional programming, have you given a look to Python? Perhaps it might sound strange to you, but it has the nice touch of a functional language, albeit not purely functional.List comprehensions and first-class functions are just natural in the language.
We, the .NET fans, have one variant of it called Boo (http://boo.codehaus.org/)that has bindings for Sharp Develop and is a fully .NET language...and I heard that is just nice to make DSLs...I just downloaded Sharp Develop and will be looking at it in more detail.
Hinted enough?
Roman,
I have heard of Boo, though I've never tried it.
You've heard of IronPython presumably: a .Net version of Python that Microsoft are creating.
I do mean to try out IronPython, but haven't got round to it yet.
Post a Comment