functional-programmingsmlsmlnj

SML: Error: types of rules don't agree when I open the Real signature


I am having this mysterious problem. I have this function in a file:

fun sum _ nil acc      = (Real.fromInt acc)
|   sum x (hd::tl) acc =  
     if x=hd orelse toUpper x=hd then sum x tl (acc+1)
     else sum x tl acc

Now, when I run the interpreter (SMLNJ) the use the file:

use "xxx.sml";

it is working perfectly and it accepts the function as it should:

val sum = fn : char -> char list -> int -> real

But when I first open the Real signature in my file:

open Real

fun sum _ nil acc      = (fromInt acc)
|   sum x (hd::tl) acc =  
     if x=hd orelse toUpper x=hd then sum x tl (acc+1)
     else sum x tl acc

it stops working and throws this error:

[opening temp2.sml]
xxx.sml:10.49-10.54 Error: operator and operand don't agree [overload conflict]
  operator domain: real * real
  operand:         real * [int ty]
  in expression:
    acc + 1
xxx.sml:8.5-11.23 Error: types of rules don't agree [tycon mismatch]
  earlier rule(s): char * char list * int -> real
  this rule: char * char list * real -> 'Z
  in rule:
    (x,:: (hd,tl),acc) =>
      if (x = hd) orelse (toUpper <exp> = hd)
      then ((sum <exp>) tl) (acc + 1)
      else ((sum <exp>) tl) acc

uncaught exception Error
  raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
             ../compiler/TopLevel/interact/evalloop.sml:44.55
             ../compiler/TopLevel/interact/evalloop.sml:292.17-292.20

First thing that seems mysterious here is that the interpreter does not show opening Real etc etc when I type use "xxx.sml"; But, what is even more mysterious is that even if I write Real.fromInt acc inside the first rule of the function (while the Real signature is open) it still refuses to work. Could someone please help me with this because it would be great if I could have the Real signature open for the whole program.


Solution

  • The Real structure implements + with type real * real -> real.

    You use this operator on your acc argument, so it is inferred to be of type real. But you also apply the Real.fromInt function with type int -> real to acc so from that it infers that acc must be an int.

    Thus your type mismatch.

    You have seen firsthand now that opening structures can have unintended side-effects. Avoiding these is a big part of why we organize code into structures. Opening it may seem like a convenience, but it comes with a price.