makestring was present in some of the early drafts of Standard ML but was removed before the final version. Poly/ML retained it as PolyML.makestring and this works on any type including structured types.
With this particular example it's possible to write
fun assert(testName, actual, expect) =
if actual = expect
then true
else raise AssertionErrorException(testName ^ " failed. actual: " ^
PolyML.makestring actual ^ ", expect: " ^
PolyML.makestring expect);
So
assert("test1", SOME [], NONE);
prints
Exception-
AssertionErrorException "test1 failed. actual: SOME [], expect: NONE"
raised
This happens to work because the type of actual and expect are equality types and this gives the compiler enough information to print the values properly. In general, though, if PolyML.makestring is included in a polymorphic function all that will be printed is "?". The solution is to pass in an extra parameter that is a function to convert the particular type to string.
fun assert(testName, actual, expect, toString) =
if actual = expect
then true
else raise AssertionErrorException(testName ^ " failed. actual: " ^
toString actual ^ ", expect: " ^ toString expect );
You then need to pass in a function that will convert the particular values into strings. In Poly/ML this can be PolyML.makestring.
assert("test2", (1,2,3), (1,2,4), PolyML.makestring);
prints
Exception-
AssertionErrorException
"test2 failed. actual: (1, 2, 3), expect: (1, 2, 4)" raised
If you're using a different SML implementation you could still do the same and pass in your own conversion function for the particular type.
assert("test2", (1,2,3), (1,2,4),
fn (a,b,c) =>
String.concat["(", Int.toString a, ",", Int.toString b,
",", Int.toString c, ")"]);
In effect you are implementing the type classes described in the previous answer.