Armed with our knowledge about integers and reals and the useful ``pattern matching'' mechanism of Standard ML we are now able to implement a simple formula. A Reverend Zeller discovered a formula which calculates the day of the week for a given date. If d and m denote day and month and y and c denote year and century with each month decremented by two (January and February becoming November and December of the previous year) then the day of the week can be calculated according to the following formula.
(floor (2.61m - 0.2) + d + y + y ÷ 4 + c ÷ 4 - 2c) mod 7
This is simple to encode as a Standard ML function, zc, with a four-tuple as its argument if we know where to obtain the conversion functions in the Standard ML library. We will bind these to concise identifier names for ease of use. We choose the identifier floor for the real-to-integer function and real for the integer-to-real function. Note the potential for confusion because the name real is simultaneously the name of a function and the name of a type. Standard ML maintains different name spaces for these.
val floor = Real.floor
val real = Real.fromInt
val zc =
fn (d, m, y, c) =>
(floor (2.61 * real (m) - 0.2)
+ d + y + y div 4 + c div 4 - 2 * c) mod 7;
Now we may use the pattern matching mechanism of Standard ML to perform the adjustment required for the formula to calculate the days correctly.
val zeller =
fn (d, 1, y) => zc (d, 11, (y-1) mod 100, (y-1) div 100 + 1)
| (d, 2, y) => zc (d, 12, (y-1) mod 100, (y-1) div 100 + 1)
| (d, m, y) => zc (d, m - 2, y mod 100, y div 100 + 1);
Although the zeller function correctly calculates days of the
week its construction is somewhat untidy since the floor,
real and zc
functions have the same status as the zeller function although
they were intended to be only sub-components. We require a language
construct which will bundle the four functions together, making the
inferior ones invisible. In Standard ML the local ..
in .. end construct is used for this purpose.
local
val floor = Real.floor
val real = Real.fromInt
val zc =
fn (d, m, y, c) =>
(floor (2.61 * real (m) - 0.2)
+ d + y + y div 4 + c div 4 - 2 * c) mod 7
in
val zeller =
fn (d, 1, y) => zc (d, 11, (y-1) mod 100, (y-1) div 100 + 1)
| (d, 2, y) => zc (d, 12, (y-1) mod 100, (y-1) div 100 + 1)
| (d, m, y) => zc (d, m - 2, y mod 100, y div 100 + 1)
end;
Here we have three functions declared between the keyword local
and the keyword in and one function defined between the keyword
in and the keyword end. In general we could have a
sequence of declarations in either place so a utility function could
be shared between several others yet still not be made generally
available. Either or both of the declaration sequences in
local .. in .. end can be empty.