smlsmlnjml

Multiplying real number extracted of a pair using case of in StandarML


I create a datatype and a function. The function must be able to do a multiplication according to whether the members of the pair are int(s) or real(s). I can get to work for Int, but when I add a case for Real it borks. I'm stuck here. Please help.

fun f1(pair: numberType * numberType) =
    let
        val p1 = #1 pair
        val p2 = #2 pair
    in
        case (p1, p2) of
            (Int i1, Int i2) => Int.toInt i1 * Int.toInt i2
          | (Real r1, Real r2) =>  r1 * r2
          | _ => raise Fail "Neither p1 nor p2 is of type Int or Real"
    end;

Solution

  • I'm going to assume the data type looks like the following:

    datatype numberType = 
        Int of int 
      | Real of real;
    

    All functions must have the same return type. In your function, when you pass in a tuple of Int values, you return an int. When you pass in a tuple of Real values, you return a real value. This cannot compile.

    Rather, you want to return a value of numberType built with the appropriate constructor for the data passed in.

    fun f1(pair: numberType * numberType) =
      let
        val p1 = #1 pair
        val p2 = #2 pair
      in
        case (p1, p2) of
            (Int i1,  Int i2)  => Int (i1 * i2)
          | (Real r1, Real r2) => Real (r1 * r2)
          | _ => raise Fail "Neither p1 nor p2 is of type Int or Real"
      end;
    

    This will compile but you've been much more verbose than you need to be. Let's start improving.

    fun f1(n1, n2) =
      case (n1, n2) of
          (Int i1, Int i2) => Int (i1 * i2)
        | (Real r1, Real r2) =>  Real (r1 * r2)
        | _ => raise Fail "Neither p1 nor p2 is of type Int or Real";
    

    But we can pattern match without that case expression.

    fun f1(Int i1, Int i2)   = Int (i1 * i2)
      | f1(Real r1, Real r2) = Real (r1 * r2)
      | f1 _                 = raise Fail "Neither p1 nor p2 is of type Int or Real";
    

    Your error isn't quite right though. The program will not compile at all if the arguments are not of type numberType. Rather hitting this last catchall pattern at runtime means the two values are not built using the same constructor. You can either change the error, or make this work for such a situation.

    Presumably in this case the expected output would be a Real value.

    fun f1(Int i1,  Int i2)  = Int (i1 * i2)
      | f1(Real r1, Real r2) = Real (r1 * r2)
      | f1(Int i1,  Real r2) = Real (Real.fromInt i1 * r2)
      | f1(n1, n2)           = f1(n2, n1);