Search code examples
smlsmlnj

using user-defined datatype as a type for a function argument


I have the following datatypes defined:

datatype Arguments
  = IntPair of int * int
  | RealTriple of real * real * real
  | StringSingle of string;

datatype OutputArgs = IntNum of int | RealNum of real | Str of string;

and I try to create a function MultiFunc: Arguments -> OutputArgs:

fun MultiFunc(RealTriple (x, y, z)) : OutputArgs = RealNum ((x+y+z)/3.0)
  | MultiFunc(IntPair (x,y)) : OutputArgs = IntNum (x+y)
  | MultiFunc(StringSingle(s)) : OutputArgs = Str (implode(rev(explode(s))));

However when I call MultiFunc(1.0,2.0,3.0) I get the following error:

stdIn:588.1-588.23 Error: operator and operand don't agree [tycon mismatch]
  operator domain: Arguments
  operand:         real * real * real
  in expression:
    MultiFunc (1.0,2.0,3.0)

I.e. for some reason it doesn't recognize the input argument as being a RealTriple.


Solution

  • MultiFunc(1.0,2.0,3.0)
    

    for some reason it doesn't recognize the input argument as being a RealTriple.

    That's because the input isn't a RealTriple, but a 3-tuple of reals (real * real * real).

    Try instead:

    - MultiFunc (RealTriple (1.0, 2.0, 3.0));
    > val it = RealNum 2.0 : OutputArgs
    

    Here's how I'd write the function:

    fun multiFunc (RealTriple (x, y, z)) = RealNum ((x+y+z)/3.0)
      | multiFunc (IntPair (x,y)) = IntNum (x+y)
      | multiFunc (StringSingle s) = Str (implode (rev (explode s)))
    

    By having function names start with a lowercase, I distinguish them visually from value constructors like RealTriple. I don't write : OutputArgs but let the type of the function be inferred instead. And I omit redundant parentheses like StringSingle(s) or explode(s): In many programming languages, function calls must have parentheses. In Standard ML, function application is achieved by juxtaposition of function on the left and argument on the right separated by whitespace. So f x is f being called on x, and (f x) y is "whatever f x returns, used as a function, on y."