Archive for January, 2009
F# is clearly gearing itself for science and math. Well, most functional languages do since they frequently make it easy to express mathematical formulas naturally. One thing it does well is allow for measurements to be expressed using units. For example, let’s say that we need to compute the velocity of an object falling towards Earth. Things fall towards Earth at 9.8 m/s^2. To compute the speed of an object falling towards Earth after falling a fixed distance, we would find that we can simply multiple distance * velocity and wind up with m^2/s^2. To find speed, we take the square root of the product.
A common cause of bugs when performing this kind of calculation results from losing track of the units. How do we make sure that we at least know what the units are? For this kind of problem, F# introduces the Measure attribute. Measure allows a given, empty type to represent some type of unit. To represent meter and second, we would write:
[<Measure>] type m
[<Measure>] type s
Using these measures, we can then express Earth’s gravity as a value in meters/second^2
let gravityOnEarth = 9.81<m/s^2>
We can then express speedOfImpact against these values:
let speedOfImpact height = sqrt(gravityOnEarth * height)
Then, we can do something like find the speed after falling 100.0 meters. Pulling everything together, we have this:
3 [<Measure>] type m
4 [<Measure>] type s
6 let gravityOnEarth = 9.81<m/s^2>
7 let speedOfImpact height = sqrt(gravityOnEarth * height)
9 printfn “%f” (float (speedOfImpact 100.0<m>))
This prints out
Oh, if you forget to cast the result to a float, the compiler will tell you something like this:
The unit of measure ‘m/s’ does not match the unit of measure ‘1’
m/s– that’s a speed measurement! Note: the units of measure must appear immediately after the value represented. Any white space will give you this error on the next line:
incomplete construct at or before this point in expression
Now, before you write off F# as something that you could never use in a line of business application, consider the use of Measure for sales forecasting and other forms of capacity management. Items leave warehouses with a ‘velocity’ of widgets/unit of time. Here is a trivial example:
3 [<Measure>] type widget
5 [<Measure>] type hour
6 let salesVelocity = 18.0<widget/hour>
7 let salesInTime hours= (salesVelocity * hours)
9 printfn “%f” (float (salesInTime 72.0<hour>))
You can use more sophisticated logic to determine to salesVelocity and so on. My goal isn’t to belabor the point. widgets/case, defects/hour, phone calls/second, all are units that you will use in your non-scientific, line of business applications. I sense something that may allow for better accuracy and remove another class of error from applications. I haven’t seen this example used yet by others talking about Measure. I’m trying to look beyond science and see the benefits in other types of calculations.
To allow a few of you out there to avoid the same time waster I experienced, let me state this one quickly: if you want to develop applications for Azure, you cannot run the DevFabric on Windows 7 Beta. The bug has been confirmed by Microsoft and has no known workarounds. I hit the issue exactly 5 minutes after I had finished a system rebuild to get Win 7 + VS 2008 up and running. Thankfully, I also run Windows Home Server elsewhere in the house and was able to get back to a happy place within an hour.
I know a few of you may have seen Microsoft folks running this scenario; Ron Jacobs did it at the MSDN DevCon in Chicago on Tuesday, Jan 13. Guess what: FOLKS LIKE RON AREN’T RUNNING THE BETA. They have access to internal builds that, apparently, allow one to debug Azure locally. The build we got for the beta probably last had a code update sometime in early December, if not before Thanksgiving. So, if you are digging into that awesome sauce that is Azure, don’t set up a Win 7 dev box.
When reading through the F# spec, you will see plenty of references to it’s inspiration language, Objective Caml, aka OCaml. If you want to learn more about OCaml, and by extension F#, you may find the OCaml book from O’Reilly handy. This appears to be the complete, English translation of the book… all 757 pages. I was a little curious about what OCaml is and why it exists. Fortunately, Google knew the answer. It pointed me to A History of Caml. Briefly:
“Caml” was originally an acronym for Categorical Abstract Machine Language. It was a pun on CAM, the Categorical Abstract Machine, and ML, the family of programming languages to which Caml belongs. The name Caml has remained throughout the evolution of the language, even though the present implementation has no relation with the CAM.
Apparently, OCaml was released in 1996. The fact that we are seeing it appear in .NET today as F# is nothing short of amazing. I wonder if F# projects will ever qualify for the OCaml Success Stories page.
I was reading past section 4.1 of the F# spec, Operator Names, when an idea occurred to me: can I define custom operators that have no other ‘normal’ definition? I had seen some stuff in the spec that suggested how one might do this, so I gave it a go. I constructed a nonsense operator: &^^%. Let’s look at the code first:
3 let (&^^%) x y = x + y
5 printfn “%d” (10 &^^% 32)
(Yeah, I’m a Hitchhiker’s Guide fan.) What did we really do? Well, I asked Reflector what it thought it saw. The response in C#:
I see this method:
1 public static int op_AmpHatHatPercent(int x, int y)
3 return (x + y);
and I see it being called like so:
1 FastFunc<int, Unit> func = Pervasives.printfn<FastFunc<int, Unit>>(new Format<FastFunc<int, Unit>, TextWriter, Unit, Unit, int>(“%d”));
2 int num = Program.op_AmpHatHatPercent(10, 0x20);
What I find interesting is that the compiler has a mechanism to convert the punctuation symbols into a function name. The rest seems kind of sensible/obvious. That is, the solution makes sense. This does bring up a few interesting questions:
- What is FastFunc?
- What is Pervasives?
FastFunc has this description in the docs:
The .NET type used to represent F# function values. This type is not typically used directly from F# code, though may be used from other .NET languages.
An instance of FastFunc defines an Invoke method. The type has several static/class members to do an InvokeFast with 3, 4, 5, or 6 parameters.
Pervasives represents the set of functions that are automatically visible in any F# application without making an explicit reference to the Microsoft.FSharp.Core.Pervasives namespace.
I learned how to program in C a long time ago (maybe 1992?). When diagnosing issues, I got accustomed to being able to have an exception or other message targeted at a developer to explain where the message came from. I could review the logs an know where the message was printed in the build of the system that the user had running. Using this power, I could get context with an otherwise uninformative message like
got here __FILE__:__LINE__
In 2001, I moved into .NET full time. I got garbage collection, assemblies, reflection, and so much else. I lost __FILE__ and __LINE__. I learned to push out PDBs to get file and line information when I needed it in exceptions. But, I couldn’t push those files out to production. I learned to use SOS with WinDBG and a collection of symbols to debug production issues, and I moved on. As I write this, I’m reading the F# spec. Guess what I saw in section 3.11 of the spec?
The following identifiers are automatically replaced by values in F# code:
__SOURCE_DIRECTORY__ replaced by a literal verbatim string, e.g. C:source __SOURCE_FILE__ replaced by a literal verbatim string of the filename as given to the command line compiler or on a load line, e.g. sourcefile.fs, after taking into account adjustments from line directives. __LINE__ replaced by a literal string giving the line number in the source file, after taking into account adjustments from line directives.
Here is an example of printing these values to the console.
3 printfn “Source Directory: %s” __SOURCE_DIRECTORY__
4 printfn “Source File: %s” __SOURCE_FILE__
5 printfn “Line: %s” __LINE__
The resulting output:
Source Directory: C:UsersScott SeelyDocumentsVisual Studio 2008ProjectsCloudService1TestApp
Source File: C:UsersScott SeelyDocumentsVisual Studio 2008ProjectsCloudService1TestAppProgram.fs
This is too freaking awesome! It is such a simple tool for diagnostics and it does so much. I was worried that the whole exercise in learning F# would really be some form of mental masturbation. So far, I’m seeing some real plusses. I’m also having fun.
I’m still waiting on a Storage and Hosting account with Azure. This kind of bites since I am a member of the Cloud Services Advisory Group– I’d have thought I’d get some preferential treatment, but no. Still, I am using the Windows Azure SDK to build stuff. This means that I can still experiment locally. A little while ago, while checking to see if my F# code would run OK with a cloud service, I ran into a deployment issue. I had the SQL Server Express database installed and had the Development Fabric and Development Storage up and running via VS2008. I pressed F5, Internet Explorer eventually popped up, and I saw
Internet Explorer cannot display the webpage
I then clicked on the Development Fabric, selected the Web Role, and saw this reported in the Web Role window:
Role state Suspended
Role state Started
Role state Stopping
Role state Stopped
Role state Aborted
Also, the ball next to the WebRole was blue instead of green. Blue means bad. (Aside: Is this some sophomoric gag to the team: the role has ‘blue balls’?) Frustrating! I checked that everything was configured correctly and it was. So, I asked my good friend, Google, how to solve the problem. I asked it, http://www.google.com/search?q=. You know what? It only had one answer. Here’s the issue: my home PC uses a username with a space in it. At home, I use full names as user names. Example, I am Scott Seely. This means that my user profile points to C:UsersScott Seely. The files/scripts that the Development Fabric uses do not account for spaces in temp folders, which means me and anyone else who dares put a space in their user name will suffer the same fate. The fix is to start the Development Fabric from an elevated command prompt, started from the Microsoft Service Hosting SDK Command Prompt, found under Start–>All Programs–>Microsoft Service Hosting SDK 1.0.0. Make sure that all copies of dfservice.exe are terminated. With that command prompt up, run this command:
bindevfabricdfservice -sp “C:fabrictemp”
Now, you can run your application on the fabric.
BTW, the F# code runs fine on Azure on my local machine. I still don’t know about the situation when running in the cloud, but I assume it will be no more than adding a few DLLs at most.