Carl Liu
Carl Liu

Reputation: 1

Why do I get a weird data type in sml? (?.X! instr)

datatype 'a instr = Put of 'a|Get|Restore;

fun makeCell (n:int):('a instr->unit)= 
  let val stack = ref [] in
    (fn (instruction:'a instr)=> 
    case instruction of 
      Put (x) => ((stack := x :: !stack))
      |Get => stack := []
      |Restore => (stack := []))
    end; 

val alice = makeCell 0;
alice (Put (3));
alice (Put 3);
alice (Get);
alice (Get);

it returns an error when i build:

val alice = fn : ?.X1 instr -> unit
/usr/local/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0
  raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27

/Users/Carl/Desktop/assignment 4.sml:113.1-113.16 Error: operator and operand don't agree [literal]
  operator domain: ?.X1 instr
  operand:         int instr
  in expression:
    alice (Put 3)

What Should I do to fix this problem? I have tried different approaches, but none of them have worked.

Upvotes: 0

Views: 300

Answers (1)

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66823

Types like ?.X1 are created when the value restriction is violated.

Your definition of alice creates a violation because it defines alice as something other than a value. (Your definition is a function application). Hence your alice can't be fully polymorphic.

Here's a definition that is closer:

fun alice x = (makeCell 0) x

This modification of the definition is called eta expansion.

Unfortunately, this definition makes a new cell for each call. (Your current definitions don't allow this to be observed, however.)

Here's a definition that works for your test code and uses a single cell:

val alice : int instr -> unit = makeCell 0

It doesn't make sense for alice to be fully polymorphic while using just a single ref cell. A single cell can contain values of only one type.

Upvotes: 3

Related Questions