The value restriction in ML prevents type generalization in contexts where it could break type safety. The core issue seems to arise from combining sequenced mutation and polymorphic types, as for instance in this OCaml code:
let x = ref [];; (* value restriction prevents generalization here *)
x := 1::!x;; (* type unification with int *)
x := true::!x;; (* error *)
Without the value restriction, the last line would typecheck without error since the polymorphic type for x would unify with bool. To prevent this, the type for x has to remain monomorphic.
My question is the following: would it be possible to remove the value restriction by using monads for expressing sequences of operations?
As function arguments, variables introduced through the monad's bind operation remain monomorphic throughout the whole sequence, so it seems to achieve the same effect as the value restriction without introducing special cases during generalization.
Would this work and if not, why?
Yes, this basically works, and it's how Haskell does things. However, there's a hitch: you have to make sure the reference never "escapes" the monad. Psuedocode:
The existence of run gets us right back where we started:
Haskell gets around this in two ways:
mainis already a monadic type (IO), it can just not have a runIO or similar.For the second case you have something like:
The
forall 's. ...at the type level is analogous tofun x -> .... 's is bound variable locally, so that the argument to run can't assume anything about 's. In particular, this won't type check:Because the arguments to run can't assume that they are passed the same type for
's.This requires a feature of the type system that doesn't exist in ocaml, and requires a langugae extension (Rank2Types) in Haskell.