Traffic Stop Disposition: Classification Using F# and KNN

I have already looked at the summary statistics of the traffic stop data I received from the town here.  My next stop was to try and do a machine learning exercise with the data.  One of the more interesting questions I want to answer is what factors into weather a person gets a warning or a ticket (called disposition)?  Of all of the factors that may be involved, the dataset that I have is fairly limited:

image_thumb1

Using dispositionId as the result variable, there is StopDateTime and Location (Latitude/Longitude).  Fortunately, DateTime can be decomposed into several input variables.  For this exercise, I wanted to use the following:

  • TimeOfDay
  • DayOfWeek
  • DayOfMonth
  • MonthOfYear
  • Location (Latitude:Longitude)

And the resulting variable being disposition.  To make it easier for analysis, I limited the analysis set to finalDisposition as either “verbal warning” or “citation”  I decided to do a K-Nearest Neighbor because it is regarded as an easy machine learning algorithm to learn and the question does seem to be a classification problem.

My first step was to decide weather to write or borrow the KNN algorithm.  After looking at what kind of code would be needed to write my own and then looking at some other libraries, I decided to use Accord.Net.

My next first step was to get the data via the web service I spun up here.

  1. namespace ChickenSoftware.RoadAlert.Analysis
  2.  
  3. open FSharp.Data
  4. open Microsoft.FSharp.Data.TypeProviders
  5. open Accord.MachineLearning
  6.  
  7. type roadAlert2 = JsonProvider<"http://chickensoftware.com/roadalert/api/trafficstopsearch/Sample&quot;>
  8. type MachineLearningEngine =
  9.     static member RoadAlertDoc = roadAlert2.Load("http://chickensoftware.com/roadalert/api/trafficstopsearch&quot;)

My next first step was to filter the data to only verbal warnings (7) or citations (15). 

  1.   static member BaseDataSet =
  2.       MachineLearningEngine.RoadAlertDoc
  3.             |> Seq.filter(funx -> x.DispositionId = 7 || x.DispositionId = 15)
  4.           |> Seq.map(fun x -> x.Id, x.StopDateTime, x.Latitude, x.Longitude, x.DispositionId)
  5.           |> Seq.map(fun (a,b,c,d,e) -> a, b, System.Math.Round(c,3), System.Math.Round(d,3), e)
  6.           |> Seq.map(fun (a,b,c,d,e) -> a, b, c.ToString() + ":" + d.ToString(), e)
  7.           |> Seq.map(fun (a,b,c,d) -> a,b,c, match d with
  8.                                               |7 -> 0
  9.                                               |15 -> 1
  10.                                               |_ -> 1)
  11.           |> Seq.map(fun (a,b,c,d) -> a, b.Hour, b.DayOfWeek.GetHashCode(), b.Day, b.Month, c, d)
  12.           |> Seq.toList

You will notice that I had to transform the dispositionIds from 7 and 15 to 1 and 0.  The reason why is that the KNN method in Accord.Net assumes that the values match the index position in the array.  I had to dig into the source code of Accord.Net to figure that one out.

My next step was to divide the dataset in half: one half being the training sample and the other the validation sample:

  1. static member TrainingSample =
  2.     let midNumber = MachineLearningEngine.NumberOfRecords/ 2
  3.     MachineLearningEngine.BaseDataSet
  4.         |> Seq.filter(fun (a,b,c,d,e,f,g) -> a < midNumber)
  5.         |> Seq.toList
  6.  
  7. static member ValidationSample =
  8.     let midNumber = MachineLearningEngine.NumberOfRecords/ 2
  9.     MachineLearningEngine.BaseDataSet
  10.         |> Seq.filter(fun (a,b,c,d,e,f,g) -> a > midNumber)
  11.         |> Seq.toList

The next step was to actually run the KKN.  Before I could do that though, I had to create the distance function.  Since this was my 1st time, I dropped the geocoordinates and focused only on the time of day derivatives.

  1. static member RunKNN inputs outputs input =
  2.     let distanceFunction (a:int,b:int,c:int,d:int) (e:int,f:int,g:int,h:int) =  
  3.       let b1 = b * 4
  4.       let f1 = f * 4
  5.       let d1 = d * 2
  6.       let h1 = h * 2
  7.       float((pown(a-e) 2) + (pown(b1-f1) 2) + (pown(c-g) 2) + (pown(d1-h1) 2))
  8.  
  9.     let distanceDelegate =
  10.           System.Func<(int * int * int * int),(int * int * int * int),float>(distanceFunction)
  11.     
  12.     let knn = new KNearestNeighbors<int*int*int*int>(10,2,inputs,outputs,distanceDelegate)
  13.     knn.Compute(input)

You will notice I  tried to normalize the values so that they all had the same basis.  They are not exact, but they are close.  You will also notice that I had to create a delegate from for the distanceFunction (thanks to Mimo on SO).  This is because Accord.NET was written in C# with C# consumers in mind and F# has a couple of places where the interfaces are not as seemless as one would hope.

In any event, once the KKN function was written, I wrote a function that to the validation sample, made a guess via KKN, and then reported the result:

  1. static member GetValidationsViaKKN  =
  2.     let inputs = MachineLearningEngine.TrainingInputClass
  3.     let outputs = MachineLearningEngine.TrainingOutputClass
  4.     let validations = MachineLearningEngine.ValidationClass
  5.  
  6.     validations
  7.         |> Seq.map(fun (a,b,c,d,e) -> e, MachineLearningEngine.RunKNN inputs outputs (a,b,c,d))
  8.         |> Seq.toList
  9.  
  10. static member GetSuccessPercentageOfValidations =
  11.     let validations = MachineLearningEngine.GetValidationsViaKKN
  12.     let matches = validations
  13.                     |> Seq.map(fun (a,b) -> match (a=b) with
  14.                                                 | true -> 1
  15.                                                 | false -> 0)
  16.  
  17.     let recordCount =  validations |> Seq.length
  18.     let numberCorrect = matches |> Seq.sum
  19.     let successPercentage = double(numberCorrect) / double(recordCount)
  20.     recordCount, numberCorrect, successPercentage

I then hopped over to my UI console app and looked that the success percentage.

 

  1. private static void GetSuccessPercentageOfValidations()
  2. {
  3.     var output = MachineLearningEngine.GetSuccessPercentageOfValidations;
  4.     Console.WriteLine(output.Item1.ToString() + ":" + output.Item2.ToString() + ":" + output.Item3.ToString());
  5. }

image

So there are 12,837 records in the validation sample and the classifier guessed the correct disposition 9,001 times – a success percentage of 70%

So it looks like there is something there.  However, it is not clear that this is a good classifier without further tests – specifically seeing if the how to most common case results when pushing though the classifier.  Also, I would assume to make this a true ‘machine learning’ algorithm I would have to feed the results back to the distance function to see if I can alter it to get the success percentage higher.

One quick note about methodology – I used unit tests pretty extensively to understand how the KKN works.  I created a series of tests with some sample data to see who the function reacted. 

  1. [TestMethod]
  2. public void TestKKN_ReturnsExpected()
  3. {
  4.  
  5.     Tuple<int, int, int, int>[] inputs = {
  6.         new Tuple<int, int, int, int>(1, 0, 15, 1),
  7.         new Tuple<int,int,int,int>(1,0,11,1)};
  8.     int[] outputs = { 1, 1 };
  9.  
  10.     var input = new Tuple<int, int, int, int>(1, 1, 1, 1);
  11.  
  12.     var output = MachineLearningEngine.RunKNN(inputs, outputs, input);
  13.  
  14. }

This was a big help to get me up and running (walking, really..)…

Traffic Stop Analysis Using F#

Now that I have the traffic stop services up and running, it is time to actually do something with the data.  The data set is all traffic stops in my town for 2012 with some limited information: date/time of the stop, the geolocation of the stop, and the final disposition of the stop.  The data looks like this:

image

My 1st step was to look at the Date/Time and see if there are any patterns in DayOfMonth, MonthOfYear, And TimeOfDay.  To that end, I spun up a F# project and added my 1st method that determines the total number of records in the dataset:

  1. type roadAlert = JsonProvider<"http://chickensoftware.com/roadalert/api/trafficstopsearch/Sample&quot;>
  2. type AnalysisEngine =
  3.     static member RoadAlertDoc = roadAlert.Load("http://chickensoftware.com/roadalert/api/trafficstopsearch&quot;)
  4.  
  5.     static member NumberOfRecords =
  6.         AnalysisEngine.RoadAlertDoc
  7.             |> Seq.length

Since I am a TDDer more than a REPLer, I went and wrote a covering unit test.

  1. [TestMethod]
  2. public void NumberOfRecords_ReturnsExpected()
  3. {
  4.     Int32 notEpected = 0;
  5.     Int32 actual = AnalysisEngine.NumberOfRecords;
  6.     Assert.AreNotEqual(notEpected, actual);
  7. }

A couple of things to note about this:

1) This is really an integration test, not a unit test.  I could have written the test like this:

  1. [TestMethod]
  2. public void NumberOfRecordsFor2012DataSet_ReturnsExpected()
  3. {
  4.     Int32 expected = 27778;
  5.     Int32 actual = AnalysisEngine.NumberOfRecords;
  6.     Assert.AreEqual(expected, actual);
  7. }

But that means I am tying the test to the specific data sample (in its current state) – and I don’t want to do that.

2) I am finding that my F# code has many more functions than the code written by other people – esp data scientists.  I think it has to do with contrasting methodologies.  Instead of spending time in the REPL with a small piece of code to get it right and then adding the code into the larger code base, I am writing very small piece of code in the class and then using unit tests to get it right.  The upshot of that is that there are lots of small, independently testable pieces of code – I think this stems from my background of writing production apps that are for business problems and not for academic papers.  Also, I use classes in source files versus script files because I plan to plug the code into larger .NET applications that will be written in C# and/or VB.NET.

In any event, once I has the total number of records, I went to see how they broke down into month:

  1. static member ActualTrafficStopsByMonth =
  2.     AnalysisEngine.RoadAlertDoc
  3.         |> Seq.map(fun x -> x.StopDateTime.Month)
  4.         |> Seq.countBy(fun x-> x)
  5.         |> Seq.toList

  1. [TestMethod]
  2. public void ActualTrafficStopsByMonth_ReturnsExpected()
  3. {
  4.     Int32 notExpected = 0;
  5.     var stops = AnalysisEngine.ActualTrafficStopsByMonth;
  6.     Assert.AreNotEqual(notExpected, stops.Length);
  7.  
  8. }

 

I then created a function that shows the expected number of stops by month.  Pattern matching with F# makes creating the month list a snap.  Note that is is a true unit test because I am not dependent on external data:

  1. static member Months =
  2.     let monthList = [1..12]
  3.     Seq.map (fun x ->
  4.             match x with
  5.                 | 1 | 3 | 5 | 7 | 8 | 10 | 12 -> x,31,31./365.
  6.                 | 2 -> x,28,28./365.
  7.                 | 4 | 6 | 9 | 11 -> x,30, 30./365.
  8.                 | _ -> x,0,0.                    
  9.         ) monthList
  10.     |> Seq.toList   

  1. static member ExpectedTrafficStopsByMonth numberOfStops =
  2.     AnalysisEngine.Months
  3.         |> Seq.map(fun (x,y,z) ->
  4.             x, int(z*numberOfStops))
  5.         |> Seq.toList

  1. [TestMethod]
  2. public void ExpectedTrafficStopsByMonth_ReturnsExpected()
  3. {
  4.     var stops = AnalysisEngine.ExpectedTrafficStopsByMonth(27778);
  5.     double expected = 2359;
  6.     double actual =stops[0].Item2;
  7.  
  8.     Assert.AreEqual(expected, actual);
  9. }

With the actual and expected ready to go, I then put the two side by side:

  1. static member TrafficStopsByMonth =
  2.     let numberOfStops = float(AnalysisEngine.NumberOfRecords)
  3.     let monthlyExpected = AnalysisEngine.ExpectedTrafficStopsByMonth numberOfStops
  4.     let monthlyActual = AnalysisEngine.ActualTrafficStopsByMonth
  5.     Seq.zip monthlyExpected monthlyActual
  6.         |> Seq.map(fun (x,y) -> fst x, snd x, snd y, snd y – snd x, (float(snd y) – float(snd x))/float(snd x))
  7.         |> Seq.toList

  1. [TestMethod]
  2. public void TrafficStopsByMonth_ReturnsExpected()
  3. {
  4.     var output = AnalysisEngine.TrafficStopsByMonth;
  5.     Assert.IsNotNull(output);
  6.  
  7. }

All of my unit tests ran green

image

so now I am ready to roll.  I created a quick console UI

  1. static void Main(string[] args)
  2. {
  3.     Console.WriteLine("Start");
  4.  
  5.     foreach (var tuple in AnalysisEngine.TrafficStopsByMonth)
  6.     {
  7.         Console.WriteLine(tuple.Item1 + ":" + tuple.Item2 + ":" + tuple.Item3 + ":" + tuple.Item4 + ":" + tuple.Item5);
  8.     }
  9.  
  10.     Console.WriteLine("End");
  11.     Console.ReadKey();
  12. }

image

With the output.  Obviously, a UX person could put some real pizzaz front of this data, but that is something to do another day.  If you didn’t see it in the code above, the tuple is constructed as: Month,ExpectedStops,ActualStops,Difference,%Difference.  So the real interesting thing is that September was 47% higher than expected with December 26% less.  That kind of wide variation begs for more analysis.

I then did a similar analysis by DayOfMonth:

  1. static member ActualTrafficStopsByDay =
  2.     AnalysisEngine.RoadAlertDoc
  3.         |> Seq.map(fun x -> x.StopDateTime.Day)
  4.         |> Seq.countBy(fun x-> x)
  5.         |> Seq.toList
  6.  
  7. static member Days =
  8.     let dayList = [1..31]
  9.     Seq.map (fun x ->
  10.             match x with
  11.                 | x when x < 29 -> x, 12, 12./365.
  12.                 | 29 | 30 -> x, 11, 11./365.
  13.                 | 31 -> x, 7, 7./365.
  14.                 | _ -> x, 0, 0.                 
  15.         ) dayList
  16.     |> Seq.toList     
  17.  
  18. static member ExpectedTrafficStopsByDay numberOfStops =
  19.     AnalysisEngine.Days
  20.         |> Seq.map(fun (x,y,z) ->
  21.             x, int(z*numberOfStops))
  22.         |> Seq.toList    
  23.  
  24. static member TrafficStopsByDay =
  25.     let numberOfStops = float(AnalysisEngine.NumberOfRecords)
  26.     let dailyExpected = AnalysisEngine.ExpectedTrafficStopsByDay numberOfStops
  27.     let dailyActual = AnalysisEngine.ActualTrafficStopsByDay
  28.     Seq.zip dailyExpected dailyActual
  29.         |> Seq.map(fun (x,y) -> fst x, snd x, snd y, snd y – snd x, (float(snd y) – float(snd x))/float(snd x))
  30.         |> Seq.toList

image

The interesting thing is that there are higher than expected traffic stops in the last half of the month (esp the 25th and 26th) and much lower in the 1st part of the month.

And by TimeOfDay

  1. static member ActualTrafficStopsByHour =
  2.     AnalysisEngine.RoadAlertDoc
  3.         |> Seq.map(fun x -> x.StopDateTime.Hour)
  4.         |> Seq.countBy(fun x-> x)
  5.         |> Seq.toList
  6.  
  7. static member Hours =
  8.     let hourList = [1..24]
  9.     Seq.map (fun x ->
  10.                 x,1, 1./24.
  11.         ) hourList
  12.     |> Seq.toList     
  13.  
  14. static member ExpectedTrafficStopsByHour numberOfStops =
  15.     AnalysisEngine.Hours
  16.         |> Seq.map(fun (x,y,z) ->
  17.             x, int(z*numberOfStops))
  18.         |> Seq.toList    
  19.  
  20. static member TrafficStopsByHour =
  21.     let numberOfStops = float(AnalysisEngine.NumberOfRecords)
  22.     let hourlyExpected = AnalysisEngine.ExpectedTrafficStopsByHour numberOfStops
  23.     let hourlyActual = AnalysisEngine.ActualTrafficStopsByHour
  24.     Seq.zip hourlyExpected hourlyActual
  25.         |> Seq.map(fun (x,y) -> fst x, snd x, snd y, snd y – snd x, (float(snd y) – float(snd x))/float(snd x))
  26.         |> Seq.toList

image

 

The interesting thing here is that there are much higher than expected number of traffic stops from 1-2 AM (61% and 123%) with significantly less between 8PM and midnight.  Finally, I looked at GPS location for the stops.

  1. static member ActualTrafficStopsByGPS =  
  2.     AnalysisEngine.RoadAlertDoc
  3.         |> Seq.map(fun x -> System.Math.Round(x.Latitude,3).ToString() + ":" + System.Math.Round(x.Longitude,3).ToString())
  4.         |> Seq.countBy(fun x-> x)
  5.         |> Seq.sortBy snd
  6.         |> Seq.toList
  7.         |> List.rev
  8.  
  9. static member GetVarianceOfTrafficStopsByGPS =
  10.     let trafficStopList = AnalysisEngine.ActualTrafficStopsByGPS
  11.                             |> Seq.map(fun x -> double(snd x))
  12.                             |> Seq.toList
  13.     AnalysisEngine.Variance(trafficStopList)
  14.  
  15. static member GetAverageOfTrafficStopsByGPS =
  16.     AnalysisEngine.ActualTrafficStopsByGPS
  17.         |> Seq.map(fun x -> double(snd x))
  18.         |> Seq.average

 

You can see that I rounded the Latitude and Longitude to 3 decimal places.  Using Wikipedia, saying that 4 decimals at 23N is 10.24M and 45N it is 7.87M for latitude, I imputed that 35 is 8.94M.  With 1 M = 3.28 feet, that means that 4 decimals is with 30 feet and 3 decimals is within 300 feet and 2 decimals is within 3,000 feet.  300 feet seems like a good compromise so I ran with that.

So running the average and variance and the top GPS locations:

image

With an average of 11 stops per GPS location (less than 1 a month) and a variance of 725, there does not seem be a strong relationship between GPS location and traffic stops.

The upshot of all of this analysis seems to point to avoid getting stopped it is less important where you are than when you are.  This is confirmed anecdotally too – the Town actually broadcasts when they will have heightened traffic surveillance on Twitter and the like.  Ignore open data at your own risk.  

In any event, I my next step is to run this data though a machine-learning algorithm to see if there is anything else to uncover.

Setting up an OData Service on WebAPI2 to be used by F# Type Providers

I am prepping for the F#/Data Analytics workshop on January 8th and wanted to get the data that I used for the Road Alert application beck to better shape.  By better, I mean out of that crusty WCF SOAP that I have had it in for the last 2 years.  To that end, I jumped over to Mike Wasson’s Creating an OData tutorial.  All in all, it is a good step by step guide, but I had to make some changes to get it working for me.

Change #1 is that I am not using a local database, I am using a database located on WinHost.  Therefore, I had to swap out the EF connection string.

image

One of the things I can appreciate about the template is the comments to get the routing set up (I guess there is not attribute-based routing for O-Data?)

  1.         /*
  2. To add a route for this controller, merge these statements into the Register method of the WebApiConfig class. Note that OData URLs are case sensitive.
  3.  
  4. using System.Web.Http.OData.Builder;
  5. using ChkickenSoftware.RoadAlertServices.Models;
  6. ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  7. builder.EntitySet<TrafficStop>("TrafficStop");
  8. config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
  9. */

Things were looking good when I took a departure from the tutorial and added in a couple of unit tests (Change #2).  The 1st one was fairly benign:

  1. [TestClass]
  2. public class TrafficStopControllerIntegrationTests
  3. {
  4.     [TestMethod]
  5.     public void GetTrafficStopUsingKey_ReturnsExpected()
  6.     {
  7.         TrafficStopController controller = new TrafficStopController();
  8.         var trafficStop = controller.GetTrafficStop(1);
  9.         Assert.IsNotNull(trafficStop);
  10.     }
  11. }

Note that I had to add an app.config to the test project b/c this is an integration test and I am making a real database call – a unit test would using a mocking framework.  In any event, when I went to run the test, I got a compile error – I needed to add a reference to System.Web.Http.OData to resolve the return value from the controller.  Not big thing, though I wish I could install packages from Nuget via their .dll name and not just their package name:

image

In any event, I then ran the test and I got this exception:

image

So this is another reason why EF drives me nuts.  I have to add a reference to Entity Framework (and throw some crap in the .config file)

  1. <entityFramework>
  2.   <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  3.   <providers>
  4.     <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  5.   </providers>
  6. </entityFramework>

– even thought the calling application has nothing to do with EF.  In 2014, we have such dependency drip?  Really?  In any event, once I added a reference to EF and updated the .config file, my unit/integration test ran green so I was on the right track.

I then went to fiddler and tried to call the controller:

image

Yikes, it looks like my model has to match the EF exactly

The database:

 image

And the model:

  1. public class TrafficStop
  2. {
  3.     public Int32 Id { get; set; }
  4.     public double CadCallId { get; set; }
  5.     public DateTime StopDateTime { get; set; }
  6.     public Int32 DispositionId { get; set; }
  7.     public String DispositionDesc { get; set; }
  8.     public double Latitude { get; set; }
  9.     public double Longitude { get; set; }
  10. }

 

– I assume that I should be able to override this behavior – another thing to research.

So after matching up field names, I ran fiddler and sure enough:

image

So that was pretty painless to get an OData Service up and running.  I then removed everything but the read methods and I added an auth header (you can see the value in the screen shot above), feel free to hit up the service now that it is deployed to WinHost:

    One of the coolest things about OData is that it has a .WSDL type discovery:

http://chickensoftware.com/RoadAlert/odata/$metadata

I was really missing that when we went from SOAP Services to REST

Note that I had to do a couple of more things in Tsql (remember that?) to the original data to get it ready for general consumption (and analytics).  I had to create a real date/time from the 2 varchar fields:

Update [XXXX].[dbo].[TrafficStops]
Set StopDateTime = Convert(DateTime, right (left([Date],6),2) + ‘/’ + right([Date],2) + ‘/’ + left([Date],4) + ‘ ‘ + left(Time,2) + ‘:’ + Right(left(Time,4),2) + ‘:’ + Right(left(Time,6),2))

 

I also had to add an integral value for when we do statistical analysis:

Update [XXXXX].[dbo].[TrafficStops]
Set dispositionId =
CASE 
     WHEN dispositionDesc = ‘FURTHER ACTION NECESSARY’ THEN 1
     WHEN dispositionDesc = ‘UNABLE TO LOCATE’ THEN 2
     WHEN dispositionDesc = ‘FALSE ALARM’ THEN 3
     WHEN dispositionDesc = ‘WRITTEN WARNING’ THEN 4
     WHEN dispositionDesc = ‘OTHER    SEE NOTES’ THEN 5
     WHEN dispositionDesc = ‘REFERRED TO PROPER AGENCY’ THEN 6
     WHEN dispositionDesc = ‘VERBAL WARNING’ THEN 7
     WHEN dispositionDesc = ‘NULL’ THEN 8
     WHEN dispositionDesc = ‘ARREST’ THEN 9
     WHEN dispositionDesc = ‘NO FURTHER ACTION NECESSARY’ THEN 10
     WHEN dispositionDesc = ‘CIVIL PROBLEM’ THEN 11
     WHEN dispositionDesc = ‘COMPLETED AS REQUESTED’ THEN 12
     WHEN dispositionDesc = ‘INCIDENT REPORT’ THEN 13
     WHEN dispositionDesc = ‘UNFOUNDED’ THEN 14
     WHEN dispositionDesc = ‘CITATION’ THEN 15
     WHEN dispositionDesc = ‘FIELD CONTACT’ THEN 16
     WHEN dispositionDesc = ‘BACK UP UNIT’ THEN 17
     WHEN dispositionDesc = ‘CITY ORDINANCE VIOLATION’ THEN 18
END

So now I am ready to roll with doing the analytics.

So when I say “ready to roll”, I really meant to say “ready to flail.” When we last left the show, I was ready to start consuming the data from OData using the F# type providers.   Using Fiddler, I can see the data coming out of the OData service

image_thumb1

The problem started when I went to consume the data using the F# OData Type Provider as documented here.  I got the red squiggly line of approbation when I went to create the type:

image_thumb3

with the following message:

Error    1    The type provider ‘Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders’ reported an error: error 7001: The element ‘DataService’ has an attribute ‘DataServiceVersion’ with an unrecognized version ‘3.0’.   

 

I went over to the F#-open source Google group to seek help and Isaac Abraham had this response:

WebAPI 2 now pushes out OData 3 endpoints by default, which are actually not even backwards compatible with the OData 2 standard. OData 3 was (AFAIK) released some time after the OData Type Provider was written, so I suspect it doesn’t support OData 3.

So I am stuck.  I really want to use type providers but they are behind.  I thought about if I could downgrade my WebAPI2 OData to go to OData2 standard (whatever that is).

My 1st thought was to trick out the client by removing the DataServiceVersion header like so:

  1. public class HeadersHandler : DelegatingHandler
  2. {
  3.     async protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  4.     {
  5.         HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
  6.        
  7.         response.Content.Headers.Remove("DataServiceVersion");
  8.         return response;
  9.     }
  10.  
  11. }

The header was removed, but alas, the RSLA is still with me with the same message.  I then thought, perhaps I can go back to the old version of Json so I modified the header like so:

  1. public class HeadersHandler : DelegatingHandler
  2. {
  3.     async protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  4.     {
  5.         request.Headers.Add("Accept", "application/json;odata=verbose");
  6.  
  7.         HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
  8.        
  9.         response.Content.Headers.Remove("DataServiceVersion");
  10.         return response;
  11.     }
  12.  
  13. }

So the Json is now the “old” version, but I am still getting the RSLA.  I then ran fiddler when creating the type provider and I see this:

image_thumb7

Crap.  I need to have Entity Framework use a lower version (I am using EF 6.0).  I guess?  My 1st thought was to remove EF from the situation entirely, which is always a good idea.  My next, and more time-efficient, thought was to ask Stack Overflow – which is what I did here.  While I wait for Stack Overflow to come to the rescue. I decided to press on.  I just exposed the data via a normal controller like so:

  1. public class TrafficStopSearchController : ApiController
  2. {
  3.     public List<TrafficStop> Get()
  4.     {
  5.         DataContext context = new DataContext();
  6.         return context.TrafficStops.ToList<TrafficStop>();
  7.     }
  8.     public TrafficStop Get(int id)
  9.     {
  10.         DataContext context = new DataContext();
  11.         return context.TrafficStops.Where(ts => ts.Id == id).FirstOrDefault();
  12.     }
  13.  
  14.     [HttpGet]
  15.     [Route("api/TrafficStopSearch/Sample/")]
  16.     public List<TrafficStop> Sample()
  17.     {
  18.         DataContext context = new DataContext();
  19.         return context.TrafficStops.Where(ts => ts.Id < 100).ToList();
  20.     }
  21. }

The reason I threw in the Sample method is that the F#  JSON type provider uses a sample to infer types and I didn’t want to send the entire set of data across the wire for that.  Once that was done, the traffic stop data was consumable in my F# application like so:

  1. type roadAlert = JsonProvider<"http://chickensoftware.com/roadalert/api/trafficstopsearch/Sample&quot;>
  2. type AnalysisEngine =
  3.     static member RoadAlertDoc = roadAlert.Load("http://chickensoftware.com/roadalert/api/trafficstopsearch&quot;)

Once/if I get the OData set up, I will swap this out but this is good enough for now – after all the interesting piece is not getting the data – but doing something with it!

 

Correlation Between Recruit Rankings and Final Standings in Big Ten Football

Following up on my last post about screen scraping college football in F#, I took the next step and analyzed the data that I scraped.  I am a big believer in Domain Specific Language so ‘Rankings’ means the ranking assigned by Rivals about how well a school recruits players.  ‘Standings’ means the final position in the Big Ten after the games have been played.  Ranking is for recruiting and standings is for actually playing the games.

Going back to the code, the 1st thing I did was to separate the Standings call from the search for a given school – so that the XmlDocument is loaded once and then searched several times versus loading it for each search.  This improved performance dramatically:

  1. static member getAnnualConferenceStandings(year:int)=
  2.     let url = "http://espn.go.com/college-football/conferences/standings/_/id/5/year/&quot;+year.ToString()+"/big-ten-conference";         
  3.     let request = WebRequest.Create(Uri(url))
  4.     use response = request.GetResponse()
  5.     use stream = response.GetResponseStream()
  6.     use reader = new IO.StreamReader(stream)
  7.     let htmlString = reader.ReadToEnd()
  8.     let divMarkerStartPosition = htmlString.IndexOf("my-teams-table");
  9.     let tableStartPosition = htmlString.IndexOf("<table",divMarkerStartPosition);
  10.     let tableEndPosition = htmlString.IndexOf("</table",tableStartPosition);
  11.     let data = htmlString.Substring(tableStartPosition, tableEndPosition- tableStartPosition+8)
  12.     let xmlDocument = new XmlDocument();
  13.     xmlDocument.LoadXml(data);
  14.     xmlDocument        
  15.  
  16. static member getSchoolStanding(xmlDocument: XmlDocument,school) =
  17.     let keyNode = xmlDocument.GetElementsByTagName("td")
  18.                         |> Seq.cast<XmlNode>
  19.                         |> Seq.find (fun node -> node.InnerText = school)
  20.     let valueNode = keyNode.NextSibling
  21.     let returnValue = (keyNode.InnerText, valueNode.InnerText)
  22.     returnValue
  23.  
  24. static member getConferenceStandings(year:int) =
  25.     let xmlDocument = RankingProvider.getAnnualConferenceStandings(year)
  26.     Seq.map(fun school -> RankingProvider.getSchoolStanding(xmlDocument,school)) RankingProvider.schools
  27.         |> Seq.sortBy snd
  28.         |> Seq.toList
  29.         |> List.rev
  30.         |> Seq.mapi(fun index (school,ranking) -> school, index+1)
  31.         |> Seq.sortBy fst
  32.         |> Seq.toList

Thanks for Valera Kolupaev for showing me how to use mapi to create a tuple from the list of schools and what rank they were in the list in getConferenceStandings().

I then went to the rankings call and added a way to parse down only the schools I am interested in.  That way I can compare individual schools, groups of schools, or the entire conference:

  1. static member getConferenceRankings(year) =
  2.     RankingProvider.schools
  3.             |> Seq.map(fun schoolName -> RankingProvider.getSchoolInSequence(year, schoolName))
  4.             |> Seq.toList
  5.     
  6.  
  7. static member getSchoolInSequence(year, schoolName) =
  8.     RankingProvider.getRecrutRankings(year)
  9.                     |> Seq.find(fun (school,rank) -> school = schoolName)

After these two refactorings, my unit tests still ran green so I was ready to do the analysis.

image

I went out to my project of a couple of weeks ago for correlation and copied in the module.  The Correlation function takes in two lists of doubles.  The first list would be a school’s ranking and the second would be the standings:

  1. static member getCorrelationBetweenRankingsAndStandings(year, rankings, standings ) =
  2.     let ranks = Seq.map(fun (school,rank) -> rank) rankings
  3.     let stands = Seq.map(fun (school,standing) -> standing) standings
  4.     Calculations.Correlation(ranks,stands)
  5.  
  6. static member getCorrelation(year:int) =
  7.     let rankings = RankingProvider.getConferenceRankings year
  8.                     |> Seq.map(fun (school,rank) -> school,Convert.ToDouble(rank))
  9.     let standings = RankingProvider.getConferenceStandings(year+RankingProvider.yearDifferenceBetwenRankingsAndStandings)
  10.                     |> Seq.map(fun (school, standing) -> school, Convert.ToDouble(standing))
  11.     let correlation = RankingProvider.getCorrelationBetweenRankingsAndStandings(year,rankings, standings)
  12.     (year, correlation)

A couple of things to note:

1) This function assumes that both the rankings and the standings are the same length and are in order by school name.  A production application would check this as part of standard argument validation.

2) I used Convert.ToDouble() to change the Int32 of the ranking to Double of the correlation function.  Having these .NET assemblies available at key points in the application really moved things along.

In any event, all that was left was to list the Big Ten schools to analyze, the number of years to analyze, and the year difference between the recruit rankings and the standings from the games they played in.

As a first step, I did all original big ten schools with 7 years of recruiting and a 1,2,3,4 years difference (2002 ranking compared to 2003, 2004,2005,2006 standings ,etc…):

imageimage

imageimage

The average is .3303/.2650/.5138/.6065

And so yeah – there is a really strong correlation between a recruit ranking and the outcome on the field.  Also, the most impact the class has seems to be senior year – which makes sense.  I don’t have a hypothesis on why it drops sophomore year – perhaps the ‘impact freshmen’ leave after 1 year?

Also of interest, the correlation does not seem to follow a normal distribution.  If you only look at the schools that have an emphasis on academics, the correlation drops significantly – to a negative correlation! 

imageimage

imageimage

The average is .1485/-.1446/-.2817/-.0381

So another great reason to create the new big ten – sometimes there is a really good recruit class does not do well on the field and other times a poorly-ranked recruiting class does well on the field.  This kind of unpredictability is both exciting and probably much more likely to bring in the casual fans.

Based on this analysis, here is what is going to happen in the Big Ten next year:

  • Michigan State and Ohio State will be the leaders
  • Michigan and Penn State are in the best position beat Michigan State and Ohio State

But you didn’t need a statistical analysis to tell you that.  The one key surprise that this analysis tells you is that

  • Nebraska will have a significant improvement in the standings in 2014
  • Indiana will have a significant improvement in the standings in 2015 and 2016

As a final note, I got this after doing a bunch of requests to Yahoo:

image

image

 

So I wonder if I hit the page too many times and my IP was flagged a as a bot?  I waited a day for the server to reset to finish my analysis.  Perhaps this is a case where I should get the data when the getting is good and take their pages and bring them locally?

 

Screen Scraping College Football Statistics

As a follow-up to my post of the correlation of Academic Ranking and Football Rankings in the Big Ten, I thought I would look that the relationship between two different kinds of Football Rankings: the recruiting ranking assigned by Rivals and the actual results on the field.  To that end, I went to collect the data programmically because I am doing a time-series analysis and I didn’t want to do data-entry.

My first stop was to find a free service that exposes this data on the web.  No luck – either the data was a service that cost money or the data was presented as a web page.  Since I have never screen-scraped using F# (and I am cheap), I chose option #2.

My first data point was the recruiting ranking found here.  When I inspected the source of the page, I caught a break – the data is actually stored as Json on the page.

 image

So firing up Visual Studio, I created a solution with 1 F# project and 2 C# projects:

image

I then wrote a unit test to check that something is being returned:

  1. [TestMethod]
  2. public void getRecrutRankings_RetunsExpected()
  3. {
  4.     var rankings = RankingProvider.getRecrutRankings("2012");
  5.     Assert.AreNotEqual(0, rankings.Length);
  6. }

I then went over the F#.  I created the RankingProvider type and then add a function that pulls in the rankings for a given year:

  1. static member getRecrutRankings(year) =
  2.     let url = "http://sports.yahoo.com/footballrecruiting/football/recruiting/teamrank/&quot;+year+"/BIG10/all";
  3.     let request = WebRequest.Create(Uri(url))
  4.     use response = request.GetResponse()
  5.     use stream = response.GetResponseStream()
  6.     use reader = new IO.StreamReader(stream)
  7.     let htmlString = reader.ReadToEnd()
  8.     let startPosition = htmlString.IndexOf("var rankingsTableData =")
  9.     let headerLength = 23
  10.     let endPosition = htmlString.IndexOf(";",startPosition)
  11.     let data = htmlString.Substring(startPosition+headerLength,endPosition-startPosition-headerLength).Trim()
  12.     let results = JsonConvert.DeserializeObject(data)
  13.     let castedResults = results :?> Newtonsoft.Json.Linq.JArray
  14.                                             |> Seq.map(fun x -> (x.Value("name").ToString(), Int32.Parse(x.Value("rank").ToString())))
  15.                                             |> Seq.toList

 

A couple of things to note.

  • Lines 2 through 12 are language-agnostic.  You would write the exact same code in C#/VB.NET with a slightly different syntax.
  • Line 13 is where things get interesting.  I used the :?> operator to cast the Json to a typed structure.  :?> wins as the weirdest symbol I have ever used in computer programming.   I guess I haven’t been programming long enough?
  • Lines 14 and 15 is where you can see why F# is better than C#.  I created a function that takes the Json and pushes it into a tuple.  With no iteration, the code is both easier to read and less likely to have bugs

Hoping to press my luck, I went over the the other page (the one that holds the standings from the actual games) to see if they used Json.  No dice – so back to mid-2000s screen scraping.  I created a function that loads the table into an XML document and then searches for a given school.

  1. static member getConferenceStanding(year, school) =
  2.     let url = "http://espn.go.com/college-football/conferences/standings/_/id/5/year/&quot;+year+"/big-ten-conference";         
  3.     let request = WebRequest.Create(Uri(url))
  4.     use response = request.GetResponse()
  5.     use stream = response.GetResponseStream()
  6.     use reader = new IO.StreamReader(stream)
  7.     let htmlString = reader.ReadToEnd()
  8.     let divMarkerStartPosition = htmlString.IndexOf("my-teams-table");
  9.     let tableStartPosition = htmlString.IndexOf("<table",divMarkerStartPosition);
  10.     let tableEndPosition = htmlString.IndexOf("</table",tableStartPosition);
  11.     let data = htmlString.Substring(tableStartPosition, tableEndPosition- tableStartPosition+8)
  12.     let xmlDocument = new XmlDocument();
  13.     xmlDocument.LoadXml(data);
  14.     let keyNode = xmlDocument.GetElementsByTagName("td")
  15.                     |> Seq.cast<XmlNode>
  16.                     |> Seq.find (fun node -> node.InnerText = school)
  17.     let valueNode = keyNode.NextSibling
  18.     (keyNode.InnerText, valueNode.InnerText)

A couple of things to note:

  • Lines 2-7 are identical to the prior function so they should be combined into a single function that can be independently testable.
  • Lines 8-13 are language-agnostic.  You would write the exact same code in C#/VB.NET with a slightly different syntax.
  • Lines 14-18 is where F# really shines.  Like the prior function, by using functional programming techniques in F#, I saved myself time, avoid bugs, and made the code much more intuitive.
  • I am making a web call for each function call– this should be optimized so the call is made once and the xmlDocument is passed in.  This would also make the function much more testable (even without a mocking framework)

Next up, I needed to call this function for each of the Big Ten Schools:

  1. static member getConferenceStandings(year)=
  2.     let schools =[|"Nebraska";"Michigan";"Northwestern";"Michigan State";"Iowa";
  3.         "Minnesota";"Ohio State";"Penn State";"Wisconsin"; "Purdue"; "Indiana"; "Illinois"|]
  4.     Seq.map(fun school -> RankingProvider.getConferenceStanding(year,school)) schools
  5.         |> Seq.sortBy snd
  6.         |> Seq.toList
  7.         |> List.rev

 

This is purely F# and is a pure joy to write (and look the least amount of time).  Note that the sort is on the second element of the tuple and that the list is reversed because the second element is the wins-losses so F# is sorting ascending on the number of wins.  Since Seq does not have a rev function, I turned it into a List, which does have the rev function

Some might ask “Why didn’t you use type-providers?”  My answer is “I tried, but I couldn’t get them to work.”  For example, here is the code that I used for the type provider when parsing the xmlDocument:

  1. xmlDocument.LoadXml(data);
  2. let document = XmlProvider<xmlDocument>

The problem is that the type provider expects a uri (and I can’t find an overload to pass in the document).  It looks like type providers are more designed for providers that are ready to, well, provide (Web Services, Databases, etc..) versus jerry-rigged data (like screen scraping).

In any event, with these two functions, ready, I went to the UI project and decided to see how the teams did in 2012 on the field compared to how the teams did in recruiting 2 years before:

  1. static void Main(string[] args)
  2. {
  3.     Console.WriteLine("Start");
  4.  
  5.     Console.WriteLine("——-Rankings");
  6.     var rankings = RankingProvider.getRecrutRankings("2010");
  7.     foreach (var school in rankings)
  8.     {
  9.         Console.WriteLine(school.Item1 + ":" + school.Item2);
  10.     }
  11.  
  12.     Console.WriteLine("——-Standings");
  13.     var standings = RankingProvider.getConferenceStandings("2012");
  14.     foreach (var school in standings)
  15.     {
  16.         Console.WriteLine(school.Item1 + ":" + school.Item2);
  17.     }
  18.  
  19.     Console.WriteLine("End");
  20.     Console.ReadKey();
  21. }

And the results:

image

I have no idea if a 2-year lag between recruiting and rankings is the right number – perhaps an analysis of the correct lag will be done.  After all, between red-shirt freshmen, transfer rules, and attrition, there are plenty of variables the determine when a recruiting class has the biggest impact.  Also, the standings are a blend of recruiting classes and since I am not evaluating individual players, I can’t go to that level of detail.  2 years out seems reasonable, but as Bluto famiously once said

  1. static member getBlutoQuote() =
  2.     "Seven years of college down the drain.";

:

the average might be different.  In any event, I now have the data I want so the next step is to analyze it to see if there is any correlation.  At first glance, there might be something – the top 4 schools for recruiting all finished in the top 4 in the standings – but the bottom 4 is more muddled with only Illinois doing poorly in both recruiting and the standings.

More to come…

F# and Monopoly Simulation Redux

Now that I am 4 months into my F# adventure, I thought I would revisit the monopoly simulation that I wrote in August.  There are some pretty big differences

1)  I am not using the ‘if…then’ construct at all –> rather I am using pattern matching.  For example, consider the original communityChest function:

  1. let communityChest x y =
  2.     if y = 1 then
  3.         0
  4.     else if y = 2 then
  5.         10
  6.      else
  7.         x

and the most recent one:

  1. let communityChest (tile, randomNumber) =
  2.     match randomNumber with
  3.         | 1 -> 0
  4.         | 2 -> 10
  5.         | _ -> tile

“Big deal”, you are saying to yourself (or at least I did).  But the power of pattern matching is put on display with the revised chance.  The code is much more readable and understandable.

Original:

  1. let chance x y =
  2.     if y = 1 then
  3.         0
  4.     else if y = 2 then
  5.         10
  6.     else if y = 3 then
  7.         11
  8.     else if y = 4 then
  9.         39
  10.     else if y = 5 then
  11.         x – 3
  12.     else if y = 6 then
  13.         5
  14.     else if y = 7 then
  15.         24
  16.     else if y = 8 then
  17.         if x < 5 then
  18.             5
  19.         else if x < 15 then
  20.             15
  21.         else if x < 25 then
  22.             25
  23.         else if x < 35 then
  24.             35
  25.         else
  26.             5
  27.     else if y = 9 then
  28.         if x < 12 then
  29.             12
  30.         else if x < 28 then
  31.             28
  32.         else
  33.             12
  34.     else
  35.         x

 

Revised:

  1. let goToNearestRailroad tile =
  2.     match tile with
  3.         | 36|2 -> 5
  4.         | 7 -> 15
  5.         | 17|22 -> 25
  6.         | 33 -> 35
  7.         | _ -> failwith "not on chance"
  8.  
  9. let goToNearestUtility tile =
  10.     match tile with
  11.         | 36|2|7 -> 12
  12.         | 12|22|33-> 28
  13.         | _ -> failwith "not on chance"
  14.  
  15. let chance (tile, randomNumber) =
  16.     match randomNumber with
  17.         | 1 -> 0
  18.         | 2 -> 10
  19.         | 3 -> 11
  20.         | 4 -> 39
  21.         | 5 -> tile – 3
  22.         | 6 -> 5
  23.         | 7 -> 24
  24.         | 8 -> goToNearestRailroad tile
  25.         | 9 -> goToNearestUtility tile
  26.         | _ -> tile

 

As a side note, I ditched the x and y values because they are unreadable.  When I went back to the code after 3 months, I spent way too long trying to figure out what the heck ‘x’ was.  I know that scientific code uses cryptic values, but clean code does not.  I changed them and the code became much better.

I then took a look at the move() function.  The original:

  1. let move x y z =
  2.     if x + y > 39 then
  3.         x + y – 40
  4.     else if x + y = 30 then
  5.         10
  6.     else if x + y = 2 then
  7.         communityChest 2 z
  8.     else if x + y = 7 then
  9.         chance 7 z
  10.     else if x + y = 17 then
  11.         communityChest 17 z
  12.     else if x + y = 22 then
  13.         chance 22 z
  14.     else if x + y = 33 then
  15.         communityChest 33 z
  16.     else if x + y = 36 then
  17.         chance 36 z
  18.     else
  19.         x + y  

 

and the revised:

  1. let getBoardMove (currentTile, dieTotal) =
  2.     let initialTile = currentTile + dieTotal
  3.       matchinitialTile with
  4.           | 2 ->communityChest (2, random.Next())
  5.           | 7 ->chance (7, random.Next())
  6.           | 17 ->communityChest (17, random.Next())
  7.           | 22 ->chance (22, random.Next())
  8.         | 30 -> 10
  9.           | 33 ->communityChest (2, random.Next())
  10.           | 36 ->chance (7, random.Next())
  11.         | 40|41|42|43|44|45|46|47|48|49|50|51 -> initialTile – 40
  12.         | _ -> initialTile   

 

I am not happy with line 11 above – but apparently there is not a way in F# to do this ‘>40’ or even ‘[40 .. 51]’ in the left hand side of the pattern match.

So far, the biggest changes were to make the values more understandable and to get rid of the if…then statements and replace them with pattern matching.  Both these techniques make the code more readable and understandable.  The next big change came with the actual game play itself.  The original version:

  1. let simulation =
  2.     let mutable startingTile = 0
  3.     let mutable endingTile = 0
  4.     let mutable doublesCount = 0
  5.     let mutable inJail = false
  6.     let mutable jailRolls = 0
  7.     for diceRoll in 1 .. 10000 do
  8.         let dieOneValue = random.Next(1,7)
  9.         let dieTwoValue = random.Next(1,7)
  10.         let cardDraw = random.Next(1,17)
  11.         let numberOfMoves = dieOneValue + dieTwoValue
  12.         
  13.         if dieOneValue = dieTwoValue then
  14.             doublesCount <- doublesCount + 1
  15.         else
  16.             doublesCount <- 0
  17.         if inJail = true then
  18.             if doublesCount > 1 then
  19.                 inJail <- false
  20.                 jailRolls <- 0
  21.                 endingTile <- move 10 numberOfMoves cardDraw
  22.             else
  23.                 if jailRolls = 3 then
  24.                     inJail <- false
  25.                     jailRolls <- 0
  26.                     endingTile <- move 10 numberOfMoves cardDraw
  27.                 else
  28.                     inJail <- true
  29.                     jailRolls <- jailRolls + 1
  30.         else
  31.             if doublesCount = 3 then
  32.                 inJail <- true
  33.                 endingTile <- 10
  34.             else
  35.                 endingTile <- move startingTile numberOfMoves cardDraw
  36.          
  37.         printfn "die1: %A + die2: %A = %A FROM %A TO %A"
  38.             dieOneValue dieTwoValue numberOfMoves startingTile endingTile
  39.         startingTile <- endingTile
  40.         tiles.[endingTile] <- tiles.[endingTile] + 1

You will notice that the word ‘’mutable” shows up six times.  Using the word mutable in F# is a code smell so I refactored it out like so:

  1. let rec rollDice (currentTile, rollCount, doublesCount, inJail, jailRollCount)=
  2.     let dieOneValue = random.Next(1,7)
  3.     let dieTwoValue = random.Next(1,7)
  4.     let dieTotal = dieOneValue + dieTwoValue
  5.     let newRollCount = rollCount + 1
  6.     
  7.     let newDoublesCount =
  8.         if dieOneValue = dieTwoValue then doublesCount + 1
  9.         else 0
  10.  
  11.     let newTile = getTileMove(currentTile,dieTotal,newDoublesCount,inJail,jailRollCount)
  12.     
  13.     let newInJail =
  14.         if newTile = 10 then true
  15.         else false
  16.  
  17.     let newJailRollCount =
  18.         if newInJail = inJail then jailRollCount + 1
  19.         else 0
  20.  
  21.     let targetTuple = scorecard.[newTile]
  22.     let newTuple = (fst targetTuple, snd targetTuple + 1)
  23.     scorecard.[newTile] <- newTuple
  24.  
  25.             if rollCount < 10000 then
  26.         rollDice (newTile, newRollCount, newDoublesCount, newInJail, newJailRollCount)
  27.     else
  28.         scorecard

No “mutable” (thanks to recursion) and only 1 assignment.  I also wanted to get rid of that one ‘<-‘ and Thomas Petrick was kind enough to demonstrate the correct way to do this on stack overflow.  Finally, I had to throw in a supporting function to make the decision logic account for rolling doubles that may put you in jail or may get you out of jail depending on prior state (were you in jail when you rolled doubles, were you out of jail when you rolled doubles for the 3rd time, etc…).  I spent way too much time monkeying around with a series of nest if…then statements when it hit me that I should be using tuples and pattern matching:

  1. let getTileMove (currentTile, dieTotal, doublesCount, inJail, jailRollCount) =
  2.     match (inJail,jailRollCount, doublesCount) with
  3.         | (true,3,_) -> getBoardMove(10,dieTotal)
  4.         | (true,_,_) -> 10
  5.         | (false,_,3) -> 10
  6.         | (false,_,_) -> getBoardMove(10,dieTotal)

So here if the real power of F# on display.  I can think of hundreds of applications that I have seen in C#/VB.NET that have a high cyclomatic complexity and hidden bugs that have reared their head at the most inopportune time because of complex business logic using a series of case..switch and/or if..then. statements. Even by putting step into its own function only helps partially because the code is still there –> it is just labeled better.

By using tupled pattern matching, all of that complexity goes away and we have a succinct series of statements that actually reflect how the brain thinks about the problem.  By using F#, there are fewer lines of code (and therefore fewer unit tests to maintain) and you can write code that better represents how the wetware is approaching the problem.

The Big Ten and F#

I was talking to fellow TRINUGer David Green about football schools a couple of weeks ago.  He went to Northwestern and I went to Michigan and we were discussing the relative merits of universities doing well in football.  Assuming Goro was counting, on one hand, it is great to have a sport that can bring in tons of money to the school to fund non-football sports and activities, on the second hand it keeps alumni interested in their school, on the 3rd hand it can give locals a source of pride in the school, and on the last hand it can take the focus away from the other parts of the academic institution.

I then was talking to a professor at Ohio State University – she cares absolutely zero about the football team.  I made the comment that the smartest kids in Ohio don’t go to OSU.  They will go and root for their gladiators on Saturday but when it comes down to their academic and subsequent professional success, they look elsewhere.  She agreed.

Putting those two conversations together, it put OSU and MSU’s continued success in the Big Ten in context – as the inevitable bellyaching that those teams get the short stick when compared to the SEC.  For example, OSU and MSU both would be undefeated in the Ivy League in 2013– does that mean they should be considered in the same conversation as Alabama and Auburn for the national championship?  I think the biggest problem that OSU and MSU have is that they are in the Big Ten – which historically has been about geography, academic success, and athletic competition (in that order). 

Looking at the Big Ten Schools, I pulled their most recent academic ranking for US News and World Report and their BCS Ranking.  I then went over to MathIsFun to get the recipe for correlation:

image

I then went over to Visual Studio and created a solution like so:

image

Learning from my last project, I created my unit test first to verify that the calculation is correct:

  1. [TestMethod]
  2. public void FindCorrelationUsingStandardInput_ReturnsExpectedValue()
  3. {
  4.     Double[] tempatures = new Double[12] { 14.2, 16.4, 11.9, 15.2, 18.5, 22.1, 19.4, 25.1, 23.4, 18.1, 22.6, 17.2 };
  5.     Double[] sales = new Double[12] { 215, 325, 185, 332, 406, 522, 412, 614, 544, 421, 445, 408 };
  6.  
  7.     Double expected = .9575;
  8.     Double actual = Calculations.Correlation(tempatures, sales);
  9.     Assert.AreEqual(expected, actual);
  10. }

I then hopped over to my working code and started coding:

  1. type Calculations() =
  2.     static member Correlation(x:IEnumerable<double>, y:IEnumerable<double>) =
  3.         let meanX = Seq.average x
  4.         let meanY = Seq.average y
  5.         
  6.         let a = Seq.map(fun x -> x-meanX) x
  7.         let b = Seq.map(fun y -> y-meanY) y
  8.  
  9.         let ab = Seq.zip a b
  10.         let abProduct = Seq.map(fun (a,b) -> a * b) ab
  11.  
  12.         let aSquare = Seq.map(fun a -> a * a) a
  13.         let bSquare = Seq.map(fun b -> b * b) b
  14.         
  15.         let abSum = Seq.sum abProduct
  16.         let aSquareSum = Seq.sum aSquare
  17.         let bSquareSum = Seq.sum bSquare
  18.  
  19.         let sums = aSquareSum * bSquareSum
  20.         let squareRootOfSums = sqrt(sums)
  21.  
  22.         abSum/squareRootOfSums

What I noticed is that those intermediate variables make the code much more wordy than they need to be  – so a mathematician might think that the code is too verbose– but a developer might appreciate that each step is laid out.  In fact, I would argue that a better component design would be to break out each of the steps into their own function that can be independently testable (and perhaps reused by other functions):

  1. [TestMethod]
  2. public void GetMeanUsingStandardInputReturnsExpectedValue()
  3. {
  4.     Double[] tempatures = new Double[12] { 14.2, 16.4, 11.9, 15.2, 18.5, 22.1, 19.4, 25.1, 23.4, 18.1, 22.6, 17.2 };
  5.     Double expected = 18.675;
  6.     Double actual = Calculations.Mean(tempatures);
  7.     Assert.AreEqual(expected, actual);
  8. }
  9.  
  10. [TestMethod]
  11. public void GetBothMeansProductUsingStandardInputReturnsExpectedValue()
  12. {
  13.     Double[] tempatures = new Double[12] { 14.2, 16.4, 11.9, 15.2, 18.5, 22.1, 19.4, 25.1, 23.4, 18.1, 22.6, 17.2 };
  14.     Double[] sales = new Double[12] { 215, 325, 185, 332, 406, 522, 412, 614, 544, 421, 445, 408 };
  15.  
  16.     Double expected = 5325;
  17.     Double actual = Calculations.MeanProduct(tempatures);
  18.     Assert.AreEqual(expected, actual);
  19. }
  20.  
  21. [TestMethod]
  22. public void GetMeanSquareUsingStandardInputReturnsExpectedValue()
  23. {
  24.     Double[] tempatures = new Double[12] { 14.2, 16.4, 11.9, 15.2, 18.5, 22.1, 19.4, 25.1, 23.4, 18.1, 22.6, 17.2 };
  25.     Double[] sales = new Double[12] { 215, 325, 185, 332, 406, 522, 412, 614, 544, 421, 445, 408 };
  26.  
  27.     Double expected = 177;
  28.     Double actual = Calculations.MeanSquared(tempatures);
  29.     Assert.AreEqual(expected, actual);
  30. }

I’ll leave that implementation for another day as it is already getting late.  In any event, I ran the unit test and I got red (pink, really):

image

The spreadsheet rounded and my calculation does not.  I adjusted the unit test appropriately:

  1. [TestMethod]
  2. public void FindCorrelationUsingStandardInput_ReturnsExpectedValue()
  3. {
  4.     Double[] tempatures = new Double[12] { 14.2, 16.4, 11.9, 15.2, 18.5, 22.1, 19.4, 25.1, 23.4, 18.1, 22.6, 17.2 };
  5.     Double[] sales = new Double[12] { 215, 325, 185, 332, 406, 522, 412, 614, 544, 421, 445, 408 };
  6.  
  7.     Double correlation = Calculations.Correlation(tempatures, sales);
  8.     Double expected = .9575;
  9.  
  10.     Double actual = Math.Round(correlation, 4);
  11.     Assert.AreEqual(expected, actual);
  12. }

And now I am green:

image

So going back to the original question, I took the current Big Ten Schools and put their academic rankings and football rankings side by side:

image

 

I then made a revised Big Ten that had a much higher academic ranking based on schools that play in a power football conference but still maintain high academics.

image

Note that I left Penn State out of both of these lists b/c they have a NaN for their football ranking – but they certainly have a high enough academic score to be part of the revised Big Ten.

And then when I put those values through the correlation function via a Console UI:

  1. static void Main(string[] args)
  2. {
  3.     Console.WriteLine("Start");
  4.  
  5.     Double[] academicRanking = new Double[12] { 12,28,41,41,52,62,68,69,73,73,75,101 };
  6.     Double[] footballRanking = new Double[12] { 65,41,82,19,7,61,105,36,4,34,63,37 };
  7.  
  8.     Double originalCorrelation = Calculations.Correlation(academicRanking, footballRanking);
  9.     Console.WriteLine("Original BigTen Correlation {0}", originalCorrelation);
  10.  
  11.     academicRanking = new Double[10] { 7,12,17,18,23,23,28,30,41,41 };
  12.     footballRanking = new Double[10] { 24, 65, 32, 26, 94, 84, 41, 58, 82, 19 };
  13.     Double revisedCorrelation = Calculations.Correlation(academicRanking, footballRanking);
  14.     Console.WriteLine("Revised BigTen Correlation {0}", revisedCorrelation);
  15.  
  16.     
  17.     Console.WriteLine("End");
  18.     Console.ReadKey();
  19. }

I get:

image

And just looking at the data seems to support this.  There is a negative correlation between academics and football success in the current Big Ten – Higher the academics = lower the football ranking and vice versa.  In the revised Big Ten, there is positive correlation of the same magnitude – higher academics and higher (relative) football rankings.  Put another way, the new Big Ten has a much stronger academic ranking and pretty much the same football ranking.

Looking at a map, this new conference is like a doughnut with Ohio, West Virginia, and Kentucky in the middle.  Perhaps they can have a football championship sponsored by Krispie Kreeme?  In any event, OSU and MSU are much closer academically and football-wise to the Alabamas and Auburns than the Northwesterns and Michigans of the world.  In terms of geographic proximity, Columbus, Ohio is closer to Tuscalosa, AL than Lincoln, NB.  So perhaps the OSU and MSU fans would be better served in a conference that is more aligned with their University’s priorities?  If they went undefeated or even 1 loss, they would still be in the national championship discussion.

 

 

 

F# > C# when doing math

My friend/coworker Rob Seder sent me this code project link and said it might be an interesting exercise to duplicate what he had done in F#.  Interesting indeed!  Challenge accepted!

I first created a solution like so:

image

I then copied the Variance calculation from the post to the C# implementation:

  1. public class Calculations
  2. {
  3.     public static Double Variance(IEnumerable<Double> source)
  4.     {
  5.         int n = 0;
  6.         double mean = 0;
  7.         double M2 = 0;
  8.  
  9.         foreach (double x in source)
  10.         {
  11.             n = n + 1;
  12.             double delta = x – mean;
  13.             mean = mean + delta / n;
  14.             M2 += delta * (x – mean);
  15.         }
  16.         return M2 / (n – 1);
  17.     }
  18. }

I then created a couple of unit tests for the method and made sure that the results ran green:

  1. [TestClass]
  2. public class CSharpCalculationsTests
  3. {
  4.     [TestMethod]
  5.     public void VarianceOfSameNumberReturnsZero()
  6.     {
  7.         Collection<Double> source = new Collection<double>();
  8.         source.Add(2.0);
  9.         source.Add(2.0);
  10.         source.Add(2.0);
  11.  
  12.         double expected = 0;
  13.         double actual = Calculations.Variance(source);
  14.         Assert.AreEqual(expected, actual);
  15.     }
  16.  
  17.     [TestMethod]
  18.     public void VarianceOfOneAwayNumbersReturnsOne()
  19.     {
  20.         Collection<Double> source = new Collection<double>();
  21.         source.Add(1.0);
  22.         source.Add(2.0);
  23.         source.Add(3.0);
  24.  
  25.         double expected = 1;
  26.         double actual = Calculations.Variance(source);
  27.         Assert.AreEqual(expected, actual);
  28.     }    
  29. }

 

image

 

I then spun up the same unit tests to test the F# implementation and then went over to the F# project.  My first attempt started along the lines like this:

  1. namespace Tff.BasicStats.FSharp
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type Calculations() =
  7.     static member Variance (source:IEnumerable<double>) =
  8.         let mean = Seq.average(source)
  9.         let deltas = Seq.map(fun x -> x-mean) source
  10.         let deltasSum = Seq.sum deltas
  11.         let deltasLength = Seq.length deltas
  12.         deltasSum/(double)deltasLength

 

I then realized that I was writing procedural code in F# – I was not taking advantage of the power that the expressiveness that the language provides.  I also realized that looking at the C# code to understand how to calculate Variance was useless – I was getting lost in the loop and the poorly-named variables.  I went over to Wikipedia’s definition to see if that could help me understand Variance better but I got lost in all of the formulas.  I then binged Variance on Google and one of the 1st links is MathIsFun with this explanation.  This was more like it!  Cool dog pictures and a stupid simple recipe for calculating Variance.  The steps are:

image

I hopped over to Visual Studio and wrote a one-for-one line of code to match the recipe:

  1. namespace Tff.BasicStats.FSharp
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type Calculations() =
  7.     static member Variance (source:IEnumerable<double>) =
  8.         let mean = Seq.average source
  9.         let deltas = Seq.map(fun x -> sqrt(x-mean)) source
  10.         Seq.average deltas

 

I ran the unit tests but they were running red!  I was getting a NaN. 

image

Hearing my cursing, my 7th grade son came over and said – “Dad, that is wrong.  You don’t use the square root on the (x-mean), you square it.  Also, you can’t take the square root of a negative number and any item in that list that is less than the average will return that ”  Let me repeat that – a 7th grader with no coding experience but who knows about Variance from his math class just read the code and found the problem.

I then changed the code to square the value like so:

  1. namespace Tff.BasicStats.FSharp
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type Calculations() =
  7.     static member Variance (source:IEnumerable<double>) =
  8.         let mean = Seq.average source
  9.         let deltas = Seq.map(fun x -> pown(x-mean) 2) source
  10.         Seq.average deltas

 

And now my unit test… runs…. Red!

image

Not understanding why, I turned to the REPL (F# Interactive Window).  I first entered my test set:

image

I then entered the calculation from each line against the test set:

image

Staring at the resulting array, it hit me that perhaps the original unit test’s expected value was wrong!  I went over to TutorVista and entered in my array.  Would you believe it?

image

The calculation on the code project site is incorrect!  The correct way to do the unit test is:

  1. [TestMethod]
  2. public void VarianceOfOneAwayNumbersReturnsOne()
  3. {
  4.     Collection<Double> source = new Collection<double>();
  5.     source.Add(1.0);
  6.     source.Add(2.0);
  7.     source.Add(3.0);
  8.  
  9.     //double expected = 6666666667;
  10.     double expected = 2f / 3f;
  11.     double actual = Calculations.Variance(source);
  12.     Assert.AreEqual(expected, actual);
  13. }    

 

(Note that expected was the easiest way I could come up with .6 repeating without getting all crazy on the formatting).  Now both my unit tests run green and one of the C# ones runs red. 

image

I have no interest in trying to figure out how to fix that C# code – I care less about how to solve my problem and more about just solving the problem.  The real power of F# really is on display here.  The coolest parts of this exercise were:

  • One-for-one correspondence between the steps to solve a problem and the code
  • The code is much more readable to non developers
  • By concentrating on how to solve the problem in C#, the original developer lost sight of what he was trying to accomplish.  F# focuses you on the result, not the code.
  • Unit tests can be wrong – if you let your code’s result drive the expected and not a external source. 

F# and SignalR Stock Ticker: Part 2

Following up on my prior post found here about using F# to write the Stock Ticker example found on SignalR’s website, I went to implement the heart of the application – the stock ticker class.

The original C# class suffers from a violation of command/query separation and also does a couple of things.  Breaking out the code functionality, the class creates a list of random stocks in the constructor. 

image

Then there is a timer that loops and periodically updates the current stock price. 

image

Finally, it broadcasts the new stock price to any connected clients.

image

Because the class depends on the clients for its creation and lifetime, it implements the singleton pattern – you access the class via its Instance property.  This is a very common pattern:

  1. //Singleton instance
  2. private readonly static Lazy<StockTicker> _instance =
  3.     new Lazy<StockTicker>(() =>
  4.         new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

  1. public static StockTicker Instance
  2. {
  3.     get
  4.     {
  5.         return _instance.Value;
  6.     }
  7. }

Attacking the class from a F# point of view, I first addressed the singleton pattern.  I checked out the Singleton pattern in Liu’s F# for C# Developers. The sentience that caught my eye was “An F# value is immutable by default, and this guarantees there is only on instance.” (p149)  Liu then goes and builds an example using a private class and shows how to reference it via a Instance method.  My take-away from the example is that you don’t need a Singleton pattern in F# – because everything is Singleton by default.  Another way to look at it is that a Singleton pattern is a well-accepted workaround the limitations that mutability brings when using C#.

I then jumped over to the updating stock prices – after all, how can you send out a list of new stock prices if you can’t mutate the list or the individual stocks within the list?  Quite easily, in fact.

The first thing I did was to create a StockTicker class that takes in a SignalR HubContext and a list of stocks.

  1. type StockTicker(clients: IHubConnectionContext, stocks: IEnumerable<Stock>) = class

I then added the logic to update the list and stocks.

  1. let rangePercent = 0.002
  2. let updateInterval = TimeSpan.FromMilliseconds(250.)
  3. let updateStockPrice stock:Stock =
  4.     let updateOrNotRandom = new Random()
  5.     let r = updateOrNotRandom.NextDouble();
  6.     match r with
  7.         | r when r <= 1. -> stock
  8.         | _ ->
  9.  
  10.             let random = new Random(int(Math.Floor(stock.Price)))
  11.             let percentChange = random.NextDouble() * rangePercent
  12.             let pos = random.NextDouble() > 0.51
  13.             let change = Math.Round(stock.Price * decimal(percentChange),2)
  14.             let newPrice = stock.Price + change
  15.             new Stock(stock.Symbol, stock.DayOpen, newPrice)
  16. let updatedStocks = stocks
  17.                         |> Seq.map(fun stock -> updateStockPrice(stock))

Looking at the code, the word “update” in the prior sentence is wrong.  I am not updating anything.  I am replacing the list and the stocks with the new price (if determined).  Who needs a singleton?  F# doesn’t.

I then attempted to notify the clients like so:

  1. member x.Clients = clients
  2. member x.Stocks = stocks
  3. member x.BroadcastStockPrice (stock: Stock) =
  4.     x.Clients.All.updateStockPrice(stock)

 

But I got a red squiggly line of approbation (RSLA) on the updateStockPrice method.  The compiler is complaining that

Error    1    The field, constructor or member ‘updateStockPrice’ is not defined   

And reading the SignalR explanation here:

The updateStockPrice method that you are calling in BroadcastStockPrice doesn’t exist yet; you’ll add it later when you write code that runs on the client. You can refer to updateStockPrice here because Clients.All is dynamic, which means the expression will be evaluated at runtime

So how does F# accommodate the dynamic nature of Clients.All?  I don’t know so off to StackOverflow I go….

In any event, I can then wire up a method that broadcasts the new stock prices like so:

  1. member x.BroadcastAllPrices =
  2.     x.Clients.All.updateAllStockPrices(updatedStocks)

And then write a method that calls this broadcast method every quarter second:

  1.  member x.Start =
  2.      async {
  3.             while true do
  4.              do! Async.Sleep updateInterval
  5.              x.BroadcastAllPrices
  6.      } |> Async.StartImmediate

Note that I tried to figure out the Timer class and subsequent Event for the timer, but I couldn’t.  I stumbled upon this post to ditch the timer in favor of the code above and since it works, I am all for it.  Figuring out events in F# is a battle for another day…

 

 

 

F# and SignalR Stock Ticker Example

I was looking at the server broadcast SignalR tutorial found here for a current project when I got to the StockTicker class.  In this class, the interesting code surrounds making a singleton instance because SignalR hubs are transient.  Here is the full text:

You’ll use the SignalR Hub API to handle server-to-client interaction. A StockTickerHub class that derives from the SignalR Hub class will handle receiving connections and method calls from clients. You also need to maintain stock data and run a Timer object to periodically trigger price updates, independently of client connections. You can’t put these functions in a Hub class, because Hub instances are transient. A Hub class instance is created for each operation on the hub, such as connections and calls from the client to the server. So the mechanism that keeps stock data, updates prices, and broadcasts the price updates has to run in a separate class, which you’ll name StockTicker.

So then it hit me – we need an immutable class that can handle multiple requests.  This sounds like a job for Captain F#!  Unfortunately, Captain F# is on vacation, so I went with Private 1st class F#.  So this is what I did.

I created an empty solution.  I then added in a C# Empty Web Application just to have a point of comparison to the FSharp project.  Then I added in a new F# MVC4 project from on the on-line template that Daniel Mohl created:

image

The problem is that the C# is the web app and the F# is just the controller.  Since I want a full-on double rainbow F# only MVC application, I tossed the template and just created a bare-bones F# project.  I then opened the .fsproj file and added a web ProjectType GUID (basically parroting what was in the .cs project file):

image

I posted this to stack overflow here.  So I am back to using C# as the Web application and F# as the plug in code.  I re-started with a couple of skeleton projects like so:

image

I then added a class for Stock like so:

  1. namespace Tff.SignalRServerBroadcast.FS
  2.  
  3. open System
  4.  
  5. type Stock() =
  6.     member val Symbol = String.Empty with get, set

 

I then added some unit tests to verify that I could create the Stock class and that I could assign the Symbol property:

  1. [TestClass]
  2. public class StockTests
  3. {
  4.     [TestMethod]
  5.     public void CreateStock_ReturnsValidInstance()
  6.     {
  7.         Stock stock = new Stock();
  8.         Assert.IsNotNull(stock);
  9.     }
  10.  
  11.     [TestMethod]
  12.     public void VerifyStockSymbolCanBeMutated()
  13.     {
  14.         Stock stock = new Stock();
  15.         stock.Symbol = "TEST";
  16.  
  17.         String notExpected = String.Empty;
  18.         String actual = stock.Symbol;
  19.  
  20.         Assert.AreNotEqual(notExpected, actual);
  21.     }
  22. }

 

And sure enough, they run green:

image

Just then, Captain F# swooped in from vacation and exclaimed “What are you doing?  The tenants of functional programming is immutability.  What happens if you change the Symbol after the object is created – does it really represent the same thing?  In fact, allowing the Symbol to be changed after it is created will lead to bugs and potentially unexpected behaviors in your system!”  With that, he left for a 10-day tour of the eastern Mediterranean.

I then changed the Stock class to be immutable like so:

  1. namespace Tff.SignalRServerBroadcast.FS
  2.  
  3. open System
  4.  
  5. type Stock =
  6.     {Symbol: String;
  7.      Price: Decimal;
  8.      DayOpen: Decimal;
  9.      }
  10.  
  11.      member x.GetChange () =
  12.         x.Price – x.DayOpen

 

and then updated my unit tests like so:

  1. [TestClass]
  2. public class StockTests
  3. {
  4.     [TestMethod]
  5.     public void CreateStock_ReturnsValidInstance()
  6.     {
  7.         Stock stock = new Stock("TEST", 10, 10.25M);
  8.         Assert.IsNotNull(stock);
  9.     }
  10.  
  11.     [TestMethod]
  12.     public void PriceChangeUsingValidNumbers_ReturnsCorrectChange()
  13.     {
  14.         Stock stock = new Stock("TEST", 10, 10.25M);
  15.         Decimal expected = .25M;
  16.         Decimal actual = stock.GetChange();
  17.         Assert.AreEqual(expected, actual);
  18.     }
  19. }

And then I ran my tests and got red

image

Ugh, I reversed the parameters – I intended to have the stock go up $.25.  Instead, the constructor expects the Price to come before the DayOpen.  This is not intuitive – you have implicit temporal coupleing in these parameters and since DayOpen occurs sooner in the space-time continuum, I reversed the parameters and the tests ran green:

  1. type Stock =
  2.     {Symbol: String;
  3.      DayOpen: Decimal;
  4.      Price: Decimal;
  5.      }

 

image

With that done, I looked at the last PercentChange  calculation.  The only thing remarkable about it is that the code in the on-line tutorial is incorrect.  The tutorial uses Price as the denominator, but my unit tests shows that it wrong:

  1. [TestMethod]
  2. public void PercentChangeUsingValidNumbers_ReturnsCorrectChange()
  3. {
  4.     Stock stock = new Stock("TEST", 10, 11M);
  5.     Decimal expected = .1M;
  6.     Decimal actual = stock.GetPercentChange();
  7.     Assert.AreEqual(expected, actual);
  8. }

 

image

If a stock goes from $10.00 to $11.00, it increases $1.00 and $1.00 divided by $10.00 is 10% – the stock increased 10%.

So I went back and changed the implementation to get the test to run green.

  1. member x.GetPercentChange() =
  2.     Math.Round(x.GetChange()/x.DayOpen,4)

 

image

 

So looking at this class, why is F# better than C#?

1) Less noise.  Compare the code between C# and F#

imageimage

All of the code in the Price setter is irrelevant.  In the F# implementation, you don’t need to worry about assigning DayOpen for the 1st time. 

 

2) Fewer Bugs: 

What happens if you are looking at Pets.com (IPET) on November 6, 2000 when it opened at $.16 and then went to $0.00 at noon when they finalized their liquidation?  You need to change your code b/c the C# implementation is wrong – the price was $0.00 and it was not the open price.

Also, what prevents me from changing the Symbol?  I could create a ticker class for APPL at $519 and then change the ticker to MSFT – volia MSFT’s price goes from $37.57 to $519.00!  And all of the unit tests for the Stock still run green.

3) More readable. 

Less noise – more signal (SignalR in fact)…

 

This blog post is getting a bit long so I will continue this project on another post.

Thanks to the RHCP, I listened to this 2-3 times when doing this blog post…