How to format Standard ML print output? - formatting

I am trying to format some output in Standard ML. I need to display some real values as rounded to a certain decimal place, and I also need to be able to display some real values using scientific notation.
The signature for the print function is
val it = fn : string -> unit
which doesn't seem to allow for the use of formatting codes or any other parameters. I also haven't had any luck finding documentation online. Ideally I was hoping the print function in SML would have similar functionality to printf in C...

Standard ML is a statically-typed language. It's hard to make something like printf in a type-safe way.
The SML Basis Library contains some formatting operations for numbers. But to use them is relatively verbose and relatively difficult to figure out. For example, to format a real number into a string in scientific notation with 3 places after the decimal point, you can do something like this:
Real.fmt (StringCvt.SCI (SOME 3)) 4324423423.5; (* evaluates to string "4.324E9" *)
Ugly, right?
Some implementations offer other formatting methods. For example, SML/NJ has a Format structure that allows you to use a printf-style formatting string. However, the arguments must be wrapped according to their type:
Format.format "%.3e" [Format.REAL 4324423423.5]; (* evaluates to string "4.324e09" *)
Other SML implementations might have their own custom formatting functions.

Related

Can I pass a format statement to a subroutine in Fortran?

I'd like to be able to pass a 'format' into a Fortran subroutine. Take this example:
write(6,1002) M1
1002 format(A, "M1, Mach number at boundary layer edge", f8.3)
For reasons too involved to go into here it would be useful to have a generic function to which I send a variable with a format statement that would be used to write out. I can't figure out a way of doing this.
Any ideas?
You can't really pass a format statement to a subroutine. But you can pass a format string, something like:
fmtstr = '(A, "M1, Mach number at boundary layer edge", f8.3)'
...
call mysub(args, fmtstr)
then
subroutine mysub(args, fmtstr)
...
character(*), intent(in) :: fmtstr
...
write(*,fmtstr) M1
end subroutine
Some might argue that format strings are the best modern way to handle formats in all circumstances and have retired their use of format statements entirely.
Forget FORMAT statements, use format strings
string = '(A, "M1, Mach number at boundary layer edge", f8.3)'
write(*,string) M1
You can pass strings easily to a subroutine.
Format statements are just obsolete and awkward to work with.
Also, do not use unit number 6, but *, that is much more portable.

OpenOffice Calc numeric formatting language

I am trying to display always-signed integers ('-1', '+4', etc: I'll even accept '+0') in OpenOffice Calc. I've had trouble finding exact information on the numeric formatting language used.
=TEXT(cellref;"#0")
doesn't display '+', and using "+#0" always displays '+' (it displays '-+3' for -3 in fact.)
Is there a format code for this, or do I have to write a function to handle the cases?
Here is a short but cryptic solution:
=TEXT(cellref;"\+#;\-#;0")
This is actually a three-part format code. It adds either a plus sign \+# for positive numbers, a minus sign \-# for negative numbers, or just a plain 0 for zeroes.
The syntax is described here: https://help.libreoffice.org/5.2/Common/Number_Format_Codes#Positive_and_Negative_Numbers
Another approach is to apply custom formatting, which is generally a good idea where numbers are involved, to make calculations with them easier:
"+"#;"-"#;0;General

Generating Random String of Numbers and Letters Using Go's "testing/quick" Package

I've been breaking my head over this for a few days now and can't seem to be able to figure it out. Perhaps it's glaringly obvious, but I don't seem to be able to spot it. I've read up on all the basics of unicode, UTF-8, UTF-16, normalisation, etc, but to no avail. Hopefully somebody's able to help me out here...
I'm using Go's Value function from the testing/quick package to generate random values for the fields in my data structs, in order to implement the Generator interface for the structs in question. Specifically, given a Metadata struct, I've defined the implementation as follows:
func (m *Metadata) Generate(r *rand.Rand, size int) (value reflect.Value) {
value = reflect.ValueOf(m).Elem()
for i := 0; i < value.NumField(); i++ {
if t, ok := quick.Value(value.Field(i).Type(), r); ok {
value.Field(i).Set(t)
}
}
return
}
Now, in doing so, I'll end up with both the receiver and the return value being set with random generated values of the appropriate type (strings, ints, etc. in the receiver and reflect.Value in the returned reflect.Value).
Now, the implementation for the Value function states that it will return something of type []rune converted to type string. As far as I know, this should allow me to then use the functions in the runes, unicode and norm packages to define a filter which filters out everything which is not part of 'Latin', 'Letter' or 'Number'. I defined the following filter which uses a transform to filter out letters which are not in those character rangetables (as defined in the unicode package):
func runefilter(in reflect.Value) (out reflect.Value) {
out = in // Make sure you return something
if in.Kind() == reflect.String {
instr := in.String()
t := transform.Chain(norm.NFD, runes.Remove(runes.NotIn(rangetable.Merge(unicode.Letter, unicode.Latin, unicode.Number))), norm.NFC)
outstr, _, _ := transform.String(t, instr)
out = reflect.ValueOf(outstr)
}
return
}
Now, I think I've tried just about anything, but I keep ending up with a series of strings which are far from the Latin range, e.g.:
𥗉똿穊
𢷽嚶
秓䝏小𪖹䮋
𪿝ท솲
𡉪䂾
ʋ𥅮ᦸ
堮𡹯憨𥗼𧵕ꥆ
𢝌𐑮𧍛併怃𥊇
鯮
𣏲𝐒
⓿ꐠ槹𬠂黟
𢼭踁퓺𪇖
俇𣄃𔘧
𢝶
𝖸쩈𤫐𢬿詢𬄙
𫱘𨆟𑊙
欓
So, can anybody explain what I'm overlooking here and how I could instead define a transformer which removes/replaces non-letter/number/latin characters so that I can use the Value function as intended (but with a smaller subset of 'random' characters)?
Thanks!
Confusingly the Generate interface needs a function using the type not a the pointer to the type. You want your type signature to look like
func (m Metadata) Generate(r *rand.Rand, size int) (value reflect.Value)
You can play with this here. Note: the most important thing to do in that playground is to switch the type of the generate function from m Metadata to m *Metadata and see that Hi Mom! never prints.
In addition, I think you would be better served using your own type and writing a generate method for that type using a list of all of the characters you want to use. For example:
type LatinString string
const latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01233456789"
and then use the generator
func (l LatinString) Generate(rand *rand.Rand, size int) reflect.Value {
var buffer bytes.Buffer
for i := 0; i < size; i++ {
buffer.WriteString(string(latin[rand.Intn(len(latin))]))
}
s := LatinString(buffer.String())
return reflect.ValueOf(s)
}
playground
Edit: also this library is pretty cool, thanks for showing it to me
The answer to my own question is, it seems, a combination of the answers provided in the comments by #nj_ and #jimb and the answer provided by #benjaminkadish.
In short, the answer boils down to:
"Not such a great idea as you thought it was", or "Bit of an ill-posed question"
"You were using the union of 'Letter', 'Latin' and 'Number' (Letter || Number || Latin), instead of the intersection of 'Latin' with the union of 'Letter' and 'Number' ((Letter || Number) && Latin))
Now for the longer version...
The idea behind me using the testing/quick package is that I wanted random data for (fuzzy) testing of my code. In the past, I've always written the code for doing things like that myself, again and again. This meant a lot of the same code across different projects. Now, I could of course written my own package for it, but it turns out that, even better than that, there's actually a standard package which does just about exactly what I want.
Now, it turns out the package does exactly what I want very well. The codepoints in the strings which it generates are actually random and not just restricted to what we're accustomed to using in everyday life. Now, this is of course exactly the thing which you want in doing fuzzy testing in order to test the code with values outside the usual assumptions.
In practice, that means I'm running into two problems:
There's some limits on what I would consider reasonable input for a string. Meaning that, in testing the processing of a Name field or a URL field, I can reasonably assume there's not going to be a value like 'James Mc⌢' (let alone 'James Mc🙁') or 'www.🕸site.com', but just 'James McFrown' and 'www.website.com'. Hence, I can't expect a reasonable system to be able to support it. Of course, things shouldn't completely break down, but it also can't be expected to handle the former examples without any problems.
When I filter the generated string on values which one might consider reasonable, the chance of ending up with a valid string is very small. The set of possible characters in the set used by the testing/quick is just so large (0x10FFFF) and the set of reasonable characters so small, you end up with empty strings most of the time.
So, what do we need to take away from this?
So, whilst I hoped to use the standard testing/quick package to replace my often repeated code to generate random data for fuzzy testing, it does this so well that it provides data outside the range of what I would consider reasonable for the code to be able to handle. It seems that the choice, in the end, is to:
Either be able to actually handle all fuzzy options, meaning that if somebody's name is 'Arnold 💰💰' ('Arnold Moneybags'), it shouldn't go arse over end. Or...
Use custom/derived types with their own Generator. This means you're going to have to use the derived type instead of the basic type throughout the code. (Comparable to defining a string as wchar_t instead of char in C++ and working with those by default.). Or...
Don't use testing/quick for fuzzy testing, because as soon as you run into a generated string value, you can (and should) get a very random string.
As always, further comments are of course welcome, as it's quite possible I overlooked something.

Do the builtin types (c, d, i, f, etc.) have CONVERSION_EXI_* functions? And if so, how to find them?

The WRITE statement has a lot of options, so I was wondering, does it call CONVERSION_EXIT_* functions, or how does it print the primitive data types in so many ways?
And if it does use CONVERSION_EXIT_*s, what are those?
The primitive data types (DATA foo TYPE n LENGTH 10) do not have any conversion exits (ALPHA, etc.) assigned to them.
You can choose them manually, for example with
WRITE ... TO ... USING EDIT MASK '==ALPHA'.
or they can be assigned to a data dictionary domain (transaction code SE11). In this case, they are implicitly called for example:
by the screen (dynpro) processing (unless turned off explicitly).
by WRITE
DATA(langu) = CONV syst-langu( 'E' ). " domain SYLANGU has conv.exit ISOLA
DATA text TYPE c LENGTH 2.
WRITE langu TO text. " conv.exit ISOLA converts 'E' into 'EN'
Except WRITE, ABAP itself does very little to support conversion exits - which is a good thing because the conversion should take place only at the input/output borders of the program and not internally.
It's a good idea to keep all of the data in the internal format as long as you're working on it and only convert it right before the output takes place.

Is it possible to parse a mathematical expression by using #define?

I want to make a scientific calculator in which the user enters something like 3+4*(3-5)/23 and then the calculator can return the value.
Now I'm trying to find a way to parse a string of mathematical expression. I know that there are some built parsers and algorithms but I want to know whether it's possible by using #define method.
Basically, I want to use the #define to literally remove the # and " " in a string and make it look like an expression that can be evaluated. At this stage, I won't use unknown variables like x or 3*k or a*b/c. All will be numbers and operators like 3+4 and 32 that can be directly evaluated by the compiler. Here is what I want to write in #define:
#define eval#"(x)" x
In the above code, eval is just a signal of parsing and the #"x" is the actual string that need to parse and x is a mathematical expression. After the translation, only x will remain. For example, if I write
double result = eval#"(3+4)";
the compiler will read
double result = 3+4;
(according to my understanding of #define). However, the code does not work. I suspect that the quotation marks confuse the compiler and cause the code to break. So my question is: can anyone come up with a solution using #define?
This is not possible with the preprocessor, no string manipulation besides concatenation supported.
Why would you need the #"x" syntax anyways? You can just put the expression right there in the code.
People are right, you cannot do it in direct way, however if you very want macro:
#define eval(x) [[[NSExpression expressionWithFormat:x] expressionValueWithObject:nil context:nil] doubleValue]
double result = eval(#"3+4");
#define is an invocation of the C preprocessor, which is not capable of this kind of manipulation. It almost sounds like you're trying to define an Objective-C macro that would do the same kind of thing as a LISP macro, but that's not possible. Why don't you tell us what the original problem is that you're trying to solve... I think we can probably come up with an easier way to do what you're trying to do.