Ready.

printing F# units neatly

The F# ability of verifying properness of the units of [numerical] values, sounds great, for formulas to work right -- as their examples remind of errors happening in this multi-standards-based World. Therefore, hhether you program in F#, or you are "out for shopping" for your own language, the F# units are there, worthy of mention.

But that is only half the story. The machines (or, formulas) do not rule the World by themselves, yet. So, just how we inform the machines what is right to include in computing, they should inform us rightly, too, in presenting their results, so that the decision-maker humans may work right, as well, with the data (results) they are getting out of the machines.

In other words, the F# units are there, but not very convenient/robust for printing them out, yet (so far as I know, as of this writing). The F# document (@ MS-Help, MSDN) instructing about unitizing, sounds grim about it, stating that, you would never have any "ToString()" function, because units are meant to be compile-time-only (& I don't know why some RTTI would not remember that, if it already does not, btw).

finishing with a wish

While finally reading/finishing that page (I had listened to their presentations, & had liked the idea, & the page was open in the web-browser, for weeks, if not months, among other pages), on May15,2016, I thought that, for human-readability, printing that without manually-handling everytime, is preferrable, and at least, a function could do the printing, in generic fashion. Just get a unitized value, & print that, along with its unit name. Just a list of match-statements. For example, for the "degF" format ("degrees Fahrenheit"), a 50 is printable out as 50°F (if float, not int, it prints 50.000°F, btw) because the "°F" is pairable with degF unit, within that function.

Next morning I thought that, while defining the unit, some optional format is specifiable, & the compile-time knowledge of that, is (presumably) sufficient. What forbids ToString() from existing, the non-availability of units at run-time, is no problem -- if static type-inferring works fine (just how "%A" of printf works). Just having, for example, <degF, "%.1f\u00b0F"> (if you like to print temperatures with a single digit after the period), and a US$ unit as <usd, "US$ %.2f"> (as "US$" is commonly prefixed to the number, at least, in English). Just let printf know the type, and apply the associated format, in compile-time.

in match expressions

So far, as of F# 4 (or, "Microsoft (R) F# Interactive version 14.0.23020.0"), match statements of F# accept neither of the following

| :? degF -> doWhatever
F# responds: "afrmz.IdiomsForF#.fsx(29,10): error FS0704: Expected type, not unit-of-measure"

| :? float<degF> -> doWhateverElse()
F# responds: "afrmz.IdiomsForF#.fsx(31,7): error FS0016: The type 'float<'u>' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion."

The :?() operator: I think a new operator that strictly evaluates units-of-measure, fits better than just modifying the response of that existing operator. That way, one can differentiate between unitized vs. non-unitized values, for example.

let printF x =
    | :?() degF -> printfn "%A\u00b0F" x  

    | :?() float<degF> -> printf "%.1f\u00b0F" x  
    | :?() int<degF> -> printf "%d\u00b0F" x  

    | :? float -> printf "%f" x  
    | :? int -> printf "%d" x  

where the first is sufficient if you do not care to format further (whether int or float), while the next two differentiate between float and int. The final two are the fall-back options that are not for any specific unit, and if there had been various units listed, the unitless would fall till one of the last two.

If you have been writing all of that manually at every point where you have been printing out with units, that may look like real big relief, as that is against lots of human errors. That is, the unitizing protects against mechanical errors, but if you disinform the decision-makers because of printing out with wrong unit names, that is still trouble, and therefore, automatizing that through such a simple function is real relief.

But relief as it is, some of us may find that unnecessarily tedious, because such a function (with match operator) may be necessary for other works with units, rather than for printf. If all you want is to integrate units to printf, that may seem tedious -- not only in preparing that function (every combination of every type (float, int, ...) and units, but furthermore every time you print that within some other things, you refer to that with a function invocation, and as a string

printf "temperatures have been = { %s, %s, %s }" printF(x) printF(y) printF(z)

in contrast to just

printf "temperatures have been = { %A, %A, %A }" x y z

Some may guess that tediousness is not necessarily a trouble, but for example, how people copy-&-modify large portions of their code, to write new code-blocks, may hint the trouble. F# people (in official Microsoft videos) refer to that clutter of C# or C++, as contrasted to succinctness of F#, and some people endorse their text-editors (like vi) for efficient copy-&-modify (& there are code-generators when things are automatizable), against such clutter. That is, not every word in a program is written all-new, with the freshest of mental state, but just copied-&-modified to fit the new context, when a sufficiently resembling portion is just around there in the same file or folder.

declaring & equating types

For knowing how to format a unitized value, with the optional formatting stated explicitly,

[<Measure>] type degF "%.1f\u00b0F"
[<Measure>] type degF0 "%.0f\u00b0F"
[<Measure>] type degF2 "%.2f\u00b0F"

That is great for when you know that all you want is a single format, at any context. But if you would like to re-use some temperature in multiple contexts (home, lab, ...), and then combine them into formulas, then you would not like to rewrite the same formulas for every format variety. Therefore, equivalencies should be declarable, too. Presumably, that is already doable with the syntax of the unit-functions. That is, just how you declare already that 1kg = 1000g, just declare that 1 degF = 1 degF0. Then again, things may become simpler.

If all you want is to have yet another of an existing unit-type, then one could just inherit from the existing type, by overriding its format string.

[<Measure>] 
type degF0 =
   inherit degF
   override u.str = "%.0f\x00b0F"

But that may be troubling, for example, if you find, buy, or "inherit" two libraries, that is, neither is derived from the other, but they are obviously equivalent (& you do not want to "patch" the internals of any of the libraries because there are communities that steadily extend both of them), then you have to have some operator to equate two units that have identical types. That is, not necessarily "letting sth new come to exist" but just declaring that two existing ones, already are equivalent.

If the system (F# or other language) exposes its data-structures (such as lists of type-equivalencies), then you may just hack it there, by inserting the two in the same list (imperative work). Otherwise, if you would like to do that more declaratively, a simple operator may simplify things further.

let degF ()= degF0 ()= degF2 ()= degF5

// or, equivalently, 

let degF ()= degF0 ()= degF2
let degF ()= degF5

I think the keyword in the last code block would have been sounding better if that were "declare" rather than "let" but that may be acceptable if, as in the case of (yes, logic or maths), you are using the word in the sense of "let's assume that, ..."

furthermore, w.r.t. mid80.net

I had presented frag as a "calculator" language and units would fit there.

Then again, F# itself (open-source, Apache license 2.0) is embeddable as a language into formal-net nodes, too. Snippets @ nodes.

Actually, I have always pointed out that (probably) any language would fit there, and F# is only a bit more practical, perhaps. By the way, the context of my always-pointing-out, in mid80.net (& relatedly), is against copycat82's trickery of listing Pascal-like pseudocode (and advertising that as "Guttag-like-ADT"), as if plugging in some new language into existing formal nets, itself would count as the "Ph.D."-level contribution of the importer -- "in contrast to" the (already available in the 1970s) E-nets having had predicates there, and SARA had PL/I. BTW, in 1970s, there were already, SQL (database access), YACC (parser LR), Lex, and Pascal (just plug Pascal-S.pas), as pluggable languages at formal net nodes.

I had been thinking (in 2000s & later) that, token-attributes of E-nets, are good fit as pointers, too (without extra step of marshalling), at least, when the formalnet is in a single machine (or, shared memory), and safe, if the target is not changing over time. Actually, Danthine (1980) had done modally interpreting of token-attributes, too, by imposing a variant-record structure (called "union" in C). Now, units are listable there (as they remain fixed, ever), along with the value, as pointer-to-unittypeDefinition.

Just list every even-indexed attribute (0, 2, 4, ...) as the value, & the next odd-indexed attribute as its type/unit), or alternatively, (2) at the first half vs. the second half of the attributes list, or (3) palindromic. Make sure that you standardize that to a single idiom/format, not to confuse the three (or, others). Well, actually, either (1) just write some function as a wrapper, and stick with it for every token, to refer to the token-attributes, or, (2) whenever available, just work with a software (that may resemble frozen@mid80) to see the formalnet visually and access the token-attributes through its pop-up (GUI) forms.

If the types (at the other ened of the type-formatting string pointers) are hackable by others, the format-definition strings could be assault paths -- such as in buffer-overflow attacks, btw.

list of wish-lists

Forum: . . (Fair Menu . . . . . Fault Report? . . . . . Remedy for your case . . . . . Noticed Plagiarism?)

Referring#: 0.0.1
Last-Revised (text) on May 16, 2016
-- except replacing the word "concise" (for "succinct" [1]), & activating the link to Danthine (1980) which I had thought to, but somehow forgot to activate on May 16, 2016), on May 18, 2016
Written by: Ahmed Ferzan/Ferzen R Midyat-Zilan (or, Earth) . . . @zilqarneyn
Copyright (c) 2016 Ferzan Midyat. All rights reserved.
frozen@mid80, frag, form@fix, & mid80.net are trademarks of Ferzan Midyat.
mirror