Something that F# and most other modern languages allow these days is variable names that contain what you might think of as non-traditional characters from the Unicode character set, e.g., Greek symbols such as π and τ. If you’re a C programmer, you have to settle for spelling out the name of the character:
const double PI = 3.141592654; double delta = x1 - x2;
But that’s OK, right? What’s the difference, really? The value π is one thing: it’s a universally recognized constant. But even with the example delta
above, don’t you want to name it something more descriptive, like marginOfError
anyway?
Well, yes, many times instead of using the characters verbatim from your physics textbook …
let f = m * a
… you spell it out so that the code is clearer:
let force = mass * acceleration
Likewise, even though F# allows you to write the following:
let ω = 2.0 * Math.PI * f
… it’s probably better practice to write …
let angularVelocity = 2.0 * Math.PI * frequency
What’s the point of this post then? Sure, you can use “special” characters in variable names, but so far, I’ve discouraged you from doing it!
Nevertheless there are times when it is appropriate. If you are coding up an algorithm that consists of a series of well-known equations in a certain field of study, and the more your code looks like those equations, the easier it is to check it against the literature.
Consider the following—a series of values and equations for converting latitude and longitude to universal polar stereographic (UPS) coordinates, a way of representing coordinates at the earth’s poles:
UPS coordinates consist of a hemisphere—either northern or southern—and two distance components, easting and northing, both in meters:
type Hemisphere = Northern | Southern type UpdCoord = { Hemisphere : Hemisphere Easting : float Northing : float }
Now compare the code below to the equations from the literature above:
let latLonToUps (lat : float) (lon : float) = let hemisphere = if lat < 0.0 then Southern else Northern let ϕ = abs lat let λ = lon let π = Math.PI let FN = 2000000.0 let FE = 2000000.0 let a = 6378137.0 let f = 1.0 / 298.257223563 let e_2 = f * (2.0 - f) let e = sqrt e_2 let eOver2 = e / 2.0 let Cₒ = ((2.0 * a) / sqrt (1.0 - e_2)) * (((1.0 - e) / (1.0 + e)) ** eOver2) let kₒ = 0.994 let πOver4 = π / 4.0 let esinϕ = e * (sin ϕ) let ϕOver2 = ϕ / 2.0 let tanZOver2 = (((1.0 + esinϕ) / (1.0 - esinϕ)) ** eOver2) * tan (πOver4 - ϕOver2) let R = kₒ * Cₒ * tanZOver2 let Rcosλ = R * (cos λ) let Rsinλ = R * (sin λ) let N = match hemisphere with | Northern -> FN - Rcosλ | Southern -> FN + Rcosλ let E = FE + Rsinλ { Hemisphere = hemisphere Easting = E Northing = N }
It’s not perfect: you still cannot set numerators above denominators, for instance. But isn’t that easier to compare to the literature than if we had to write out RsinLambda
or eSinPhi
?
(Note: UPS coordinates are only valid for latitudes near the poles. For simplicity, the code above does not check to make sure that the input latitude falls within those bounds. I mean, it’s complex enough as it is for the sake of exemplifying the point of this post.)
(Note: I’m aware that some of the characters in the code don’t show up correctly on all browsers, e.g., the subscript “O” and perhaps the φ. I’m working to correct that. Nevertheless you should be able to use such symbols in your source code.)
One final example of something that F# allows you to do that no other language to my knowledge allows: using single-quote marks in variable names. Why would you ever want to do such a thing? One example is derivatives. In calculus, a prime (′) indicates a first derivative, and a double prime (″) indicates the second derivative. The following is how you could represent kinematics calculations:
let x = x0 + (v * t) + (0.5 * a * (t ** 2.0)) let x' = v + (a * t) let x'' = a
Another case I’ve seen is when you have a value or function that is closely associated with another value/function in some obvious way. If they are in close proximity to each other, it doesn’t make sense to come up with wholly different names. Consider this factorial function:
let factorial n = let rec factorial' n acc = if n <= 0 then acc else factorial' (n - 1) (n * acc) factorial' n 1
The inner function does the work. The outer function is just an interface to the inner function. All the factorial
does is to make the initial call factorial'
with a little bit of setup. The factorial
function is a nice interface for the user of the function; the factorial'
name indicates to developers that it is doing the heavy lifting.
5 replies on “F# Friday – Code That Looks Like Math”
This is pretty cool. Thanks for sharing, Brad.
[…] F# Friday – Code That Looks Like Math – Brad Collins […]
So – do you have an advice, how to insert those characters instead of just copy/pasting them around? Some fancy IME?
@Christian, there’s the rub. I don’t have a nice, sweet way to do it. In Windows, I’m usually opening the Character Map, searching for the character I’m interested in, copying it from there, and pasting it into the code. Once it’s in the code, I can copy and paste to other places in the code fairly easily.
Sometimes Character Map has a key sequence (using the ALT key) that allows you to enter a special character a little more quickly. You can make yourself a list (I have one taped to my monitor) of frequently used special characters and their associated key sequences. Unfortunately, many of the characters you’re likely to be interested in don’t have key sequences (that I can figure out) without making a registry edit. And apparently that doesn’t even work in every application. See Mr. Cook’s article for details:
http://www.johndcook.com/blog/2008/08/17/three-ways-to-enter-unicode-characters-in-windows/
So then, it really comes down to how important it is for you to have code that looks enough like the equations in the book. It may not be worth the trouble. If it is, on the other hand, important for the code to be easy to *read* like the source equations, then taking a little more time to *write* it should be a trade-off you’re willing to make.
You can bookmark this page for a handy place to cut & paste Greek characters from: http://www.fileformat.info/info/unicode/block/greek_and_coptic/utf8test.htm.
Also, in all languages allowing Unicode characters in variables names you should be able to use U+02B9 ‘modifier letter prime’ and U+02BA ‘modifier letter double prime’.
I use this approach in geodesics calculations, eg http://www.movable-type.co.uk/scripts/latlong-vincenty.html.