5

I just came across these in Ch. 5 of Ullman's Elements of ML Programming. He says:

"A type variable such as 'a has two different meanings. It can mean "for every type T, there is an instance of this object with type T in place of 'a. This type variable is called generalizable."

Then he says:

"'a may also represent any one type that we choose. However, after that one type is selected, the type cannot change, even if we reuse the object whose type was described using the original type variable 'a. This type variable is called non-generalizable."

Could someone give an example of each type? Having a hard time wrapping my head around this one and understanding the distinction seems important (he builds on these definitions).

Thanks!

1 Answer 1

4

That's a result of the value restriction in SML.

As the language infers types for your program, it can find expressions that would work for any type, which it represents with type variables. The map function is a good example. (My syntax might be a bit off because I've never used SML.)

fun map f nil     = nil
  | map f (x::xs) = f x :: map f xs

Since this function works for lists of any type, it gets a type variable:

('a -> 'b) -> 'a list -> 'b list

We can use the same map function for both int list and string list—this is a generalizable type variable. One thing worth noting is the nil case: nil can as easily be an empty list of int as an empty list of string. It has the type 'a list.

In a perfect world, this is all we would have. However there's a problem: mutable references. Following the same logic as above, the following ref would have a type variable in its type too:

val x = ref nil

We expect x to be a ('a list) ref. Just like nil itself, it can as easily be a (int list) ref or a (string list) ref—or can it? The problem is that we can set references. If we can use x as if it has the more specific type (int list) ref we could set it to [1,2,3]. And then, if we could use it as a (string list) ref somewhere else, we could read out [1,2,3] to something expecting a list of strings! That's a problem.

To overcome this problem, SML has the value restriction. Roughly speaking, it means that things that don't "look" like functions can't be fully polymorphic—they can't have generalizable type variables. Instead, the type of x would be based on the first concrete type we use it with (ie (int list) ref). If we then go on and try to use x with a different concrete type, we would get an error about non-generalizable type variables.,

In a sense, a non-generalizable type variable is just a placeholder until we do use x and give it a concrete type. It's a bit confusing because it still looks like a normal type variable ('a) but gives us an error if we use it in more than one way. I think OCaml does a much better job of differentiating between the two. OCaml would infer the type of x as '_a which is syntactically different from normal type variables and makes it clear that it's just a placeholder, not a normal polymorphic value.

It's a bit of a wart in the language but something that's basically unavoidable if you want to have mutable references like that.

Sign up to request clarification or add additional context in comments.

4 Comments

Are you sure that this is what Ullman is referring to? I haven't read his book, so I don't know the context; but if he is alluding to the value restriction, then I think he's doing a very poor job of it, since 'a actually cannot represent a type variable that can't be generalized due to the value restriction. Something like (ref nil) : 'a list ref won't type-check. (You say that "OCaml does a much better job of differentiating between the two", but in fact it would be more correct to say "OCaml, unlike Standard ML, has both, and uses slightly different notations for them.")
I'm pretty sure, although I don't have the book to check the context. That's how I've seen the phrase "non-generalizable type variable" used before, and I believe some compilers actually phrase their error messages like that. (As seen here in the "Value Restriction" section.)
@ruakh: Also, in OCaml, the '_a only appears as a result of type inference (ie in error messages). You can't write a type signature like that directly either. Maybe my explanation in the answer wasn't great on that front.
Re: the term "non-generalizable": Definitely -- that's how I use it as well. But Ullman's statement seems very strange if that's what he means by it. Re: OCaml: Ah, OK, thanks for clarifying. :-)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.