What does ?. datatype mean in SML?

Viewed 49

I am writing an SML binary search tree code and I am debugging the inorder, preorder, and postorder. I keep getting an error that says:

stdIn:11.1-11.30 Error: operator and operand do not agree [tycon mismatch]
  operator domain: ?.tree * string
  operand:         tree * string
  in expression:
    preOrderWrite (t4,"tree.txt")

I know what tycon mismatch is, but I don't know why tree has a ?. in front of it. This is the tree:

val t4 = node(8, node(5, node(2, leaf, leaf), node(6, leaf, leaf)), node(11, leaf, node(12, leaf, leaf)));

And this is the code for the orders:

fun preOHelp(leaf) = []
        | preOHelp(node(data, left, right)) = [data] @ preOHelp(left) @ preOHelp(right);
    fun preOrderWrite(tree,fileName) = let
                                        val outfile = TextIO.openOut(fileName)
                                        val theList = toText(preOHelp(tree))
                                    in
                                        TextIO.output(outfile, theList); 
                                        TextIO.closeOut(outfile)
                                    end;

    inOrderWrite : tree * string -> unit*)
    fun inOHelp(leaf) = []
        |inOHelp(node( data, left, right)) = inOHelp(left) @ [data] @ inOHelp(right);
    fun inOrderWrite(tree,fileName) = let
                                        val outfile = TextIO.openOut(fileName)
                                        val theList = toText(inOHelp(tree))
                                    in
                                        TextIO.output(outfile, theList); 
                                        TextIO.closeOut(outfile)
                                    end;
                                    
    postOrderWrite : tree * string -> unit*)
    fun postOHelp(leaf) = []
        | postOHelp(node( data, left, right)) = postOHelp(left) @ postOHelp(right) @ [data];
    fun postOrderWrite(tree,fileName) = let
                                        val outfile = TextIO.openOut(fileName)
                                        val theList = toText(postOHelp(tree))
                                    in
                                        TextIO.output(outfile, theList); 
                                        TextIO.closeOut(outfile)
                                    end;

And this is the to text code:

fun toText [] = ""
        | toText[x,xs] = Int.toString(x)^" "^toText(xs);
2 Answers

What does ?. datatype mean in SML?

stdIn:11.1-11.30 Error: operator and operand do not agree [tycon mismatch]
  operator domain: ?.tree * string
  operand:         tree * string
  in expression:
    preOrderWrite (t4,"tree.txt")

To be honest, I'm not sure. I think the ?. refers to an unknown module. If you find the SML/NJ error messages hard to read, consider trying out Moscow ML.


Here are a few comments:

  • When you submit code as part of a question, make sure your example code does not depend on parts that must be guessed. In particular, the 'a node datatype is missing. It should look like this,

    datatype 'a tree = leaf | node of 'a * 'a tree * 'a tree
    
  • The function toText isn't working because of a mixup between parentheses and brackets:

    fun toText [] = ""
      | toText[x,xs] = Int.toString(x)^" "^toText(xs);
    

    should be

    fun toText [] = ""
      | toText (x::xs) = Int.toString(x) ^ " " ^ toText(xs);
    
  • There are some stray comments in the code: These lines are comments, but did not start with (*. It's obvious because they end with *), but they will seem like syntax errors until you comment them out properly:

    (* inOrderWrite : tree * string -> unit*)
    (* postOrderWrite : tree * string -> unit*)
    

After fixing those three, the code compiles.


If you want to traverse a tree and do something in each node, here is an example of pre-order folding of a tree, and writing each node value pre-order to a file:

fun preorder_treefold f acc0 leaf = acc0
  | preorder_treefold f acc0 (node (x, left, right)) =
    let val acc1 = f (x, acc0)
        val acc2 = preorder_treefold f acc1 left
        val acc3 = preorder_treefold f acc2 right
    in acc3 end

fun preorder_write_tree_to_file (tree, filename) =
    let val outfile = TextIO.openOut filename
        fun writer (s, ()) = TextIO.output (outfile, Int.toString s ^ "\n")
        val _ = preorder_treefold writer () tree
        val _ = TextIO.closeOut outfile
    in () end

It means that preOrderWrite expects a different type tree than the type called tree that is the type of t4.

This usually occurs if you happen to redefine the type in the REPL after defining a function that works on it.
(Even if two type definitions are identical, SML considers them to be distinct types.)

Example:


- datatype T = T;
datatype T = T

- val t = T;
val t = T : T

- fun f T = T;
val f = fn : T -> T

- f t;
val it = T : T

- datatype T = T;
datatype T = T

- f T;
stdIn:17.1-17.4 Error: operator and operand do not agree [tycon mismatch]
  operator domain: ?.T
  operand:         T
  in expression:
    f T

Note that t, defined earlier, has this previous type and still works with f:

- t;
val it = T : ?.T

- f t;
val it = T : ?.T

The most convenient solution is usually to restart the interpreter and load all definitions again.

Related