caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Unexpected '_a problem
@ 2006-08-01 20:47 Chris King
  2006-08-01 21:20 ` [Caml-list] " Andreas Rossberg
  0 siblings, 1 reply; 9+ messages in thread
From: Chris King @ 2006-08-01 20:47 UTC (permalink / raw)
  To: O'Caml Mailing List

Given this code:

# let create_foo () = object method foo (_: 'a) = () end;;
val create_foo : unit -> < foo : 'a -> unit > = <fun>
# let a = create_foo ();;
val a : < bar : '_a -> unit > = <obj>

the compiler determines a is monomorphic, since 'a is in a
contravariant position.  But why, when 'a is placed in a covariant
position:

# let create_bar () = object method bar (_: 'a) = () end;;
val create_bar : unit -> < bar : ('a -> unit) -> unit > = <fun>
# let b = create_bar ();;
val b : < bar : ('_a -> unit) -> unit > = <obj>

does the compiler restrict b to be monomorphic?  If I wrap everything
up in a module and abstract the type returned by create_bar (),
create_bar () works as expected and returns a polymorphic value.

Thanks,
Chris King


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-01 20:47 Unexpected '_a problem Chris King
@ 2006-08-01 21:20 ` Andreas Rossberg
  2006-08-01 22:09   ` Remi Vanicat
  0 siblings, 1 reply; 9+ messages in thread
From: Andreas Rossberg @ 2006-08-01 21:20 UTC (permalink / raw)
  To: O'Caml Mailing List

"Chris King" <colanderman@gmail.com> wrote:
>
> # let create_foo () = object method foo (_: 'a) = () end;;
> val create_foo : unit -> < foo : 'a -> unit > = <fun>
> # let a = create_foo ();;
> val a : < bar : '_a -> unit > = <obj>
>
> the compiler determines a is monomorphic, since 'a is in a
> contravariant position.  But why, when 'a is placed in a covariant
> position:

This has nothing to do with contravariance, nor with subtyping or objects at
all. What you observe is the infamous "value restriction": roughly, a
definition can only be polymorphic when its right-hand side is syntactically
a value (i.e. a function, tuple, constant, etc or combination thereof). In
your case it's an application.

Also note that in the above code, it is the object that would be
polymorphic, not the method! If you want a polymorphic method, the proper
syntax is the following:

# let create_foo () = object method foo : 'a.'a -> unit = fun _ -> () end;;
val create_foo : unit -> < foo : 'a. 'a -> unit > = <fun>
# let a = create_foo ();;
val a : < foo : 'a. 'a -> unit > = <obj>
# a#foo 5; a#foo true;;
- : unit = ()

Here, `a' is a monomorphic object with a polymorphic method.

- Andreas


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-01 21:20 ` [Caml-list] " Andreas Rossberg
@ 2006-08-01 22:09   ` Remi Vanicat
  2006-08-02  7:00     ` Alain Frisch
  2006-08-02  7:03     ` Christophe Dehlinger
  0 siblings, 2 replies; 9+ messages in thread
From: Remi Vanicat @ 2006-08-01 22:09 UTC (permalink / raw)
  To: O'Caml Mailing List; +Cc: Chris King

2006/8/1, Andreas Rossberg <AndreasRossberg@web.de>:
> "Chris King" <colanderman@gmail.com> wrote:
> >
> > # let create_foo () = object method foo (_: 'a) = () end;;
> > val create_foo : unit -> < foo : 'a -> unit > = <fun>
> > # let a = create_foo ();;
> > val a : < bar : '_a -> unit > = <obj>
> >
> > the compiler determines a is monomorphic, since 'a is in a
> > contravariant position.  But why, when 'a is placed in a covariant
> > position:
>
> This has nothing to do with contravariance, nor with subtyping or objects at
> all. What you observe is the infamous "value restriction": roughly, a
> definition can only be polymorphic when its right-hand side is syntactically
> a value (i.e. a function, tuple, constant, etc or combination thereof). In
> your case it's an application.

Nope :
# let f () = [];;
val f : unit -> 'a list = <fun>
# let x = f ();;
val x : 'a list = []

I have an application, but as it is covariant, the compiler lift the
value restriction, and make it covariant. But for a reson I don't
fully understood, one cannot do:

# let f () (_ : 'a -> unit) = ();;
val f : unit -> ('a -> unit) -> unit = <fun>
# f ();;
- : ('_a -> unit) -> unit = <fun>

and have full polymorphism (when f() type is covariant). Note that
this will work:
# type +'a t = Foo of ((('a -> unit) -> unit));;
type 'a t = Foo of (('a -> unit) -> unit)
# let f () = Foo (fun _ -> ());;
val f : unit -> 'a t = <fun>
# f ();;
- : 'a t = Foo <fun>
(we have full polymorphisme here, with a code that is mostly
equivalent to the first one, but not completely).


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-01 22:09   ` Remi Vanicat
@ 2006-08-02  7:00     ` Alain Frisch
  2006-08-02 17:57       ` Chris King
  2006-08-02  7:03     ` Christophe Dehlinger
  1 sibling, 1 reply; 9+ messages in thread
From: Alain Frisch @ 2006-08-02  7:00 UTC (permalink / raw)
  To: Remi Vanicat; +Cc: O'Caml Mailing List, Chris King

Remi Vanicat wrote:
> But for a reson I don't
> fully understood, one cannot do:
> 
> # let f () (_ : 'a -> unit) = ();;
> val f : unit -> ('a -> unit) -> unit = <fun>
> # f ();;
> - : ('_a -> unit) -> unit = <fun>


See the paper _Relaxing the value restriction_ by Jacques Garrigue (
http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/morepoly-long.pdf
), page 15: dangerous type variables (which are not generalized when the
right-hand side of the let-binding is not a value) are not only those is
contravariant position - this would be enough to ensure type soundness -
but also those which appear in a contravariant branch (e.g. anywhere on
the left of an arrow) - this is necessary to ensure that the type system
has principal types.

Let me reformulate the example given in the paper. Consider the
top-level binding:

let f = print_newline (); fun x -> raise Exit

Semantically, it would be sound to give g a polymorphic type:
\forall 'a,'b. 'a -> 'b. However, the relaxed value restriction does not
try to be that clever; it decides which variables to generalize only by
looking at the type of the bound expression (when it is not a
syntactical value). Here are two possible types for the expression:

'a -> 'b
('c -> 'd) -> 'b

Generalizing all variables in covariant positions would give these two
type schemes:

\forall 'b.    'a -> 'b           ('a monomorphic)
\forall 'b,'c. ('c -> 'd) -> 'b   ('d monomorphic)

The only type-scheme which is more general than these two
would be \forall 'a,'b. 'a -> 'b, but this one is not ok (a
contravariant variable has been generalized).

To retrieve principality, the type system has been designed so that
the variable 'c above would not be generalized (it is on the left of an
arrow), which makes the type scheme \forall 'b. ('c -> 'd) -> 'b
less general than \forall 'b. ('a -> 'b) (which is the principal type
scheme inferred by OCaml).


-- Alain


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-01 22:09   ` Remi Vanicat
  2006-08-02  7:00     ` Alain Frisch
@ 2006-08-02  7:03     ` Christophe Dehlinger
  2006-08-02  8:07       ` Andreas Rossberg
  1 sibling, 1 reply; 9+ messages in thread
From: Christophe Dehlinger @ 2006-08-02  7:03 UTC (permalink / raw)
  To: Remi Vanicat; +Cc: O'Caml Mailing List

[-- Attachment #1: Type: text/plain, Size: 2936 bytes --]

On 8/2/06, Remi Vanicat <remi.vanicat@gmail.com > wrote:
>
> 2006/8/1, Andreas Rossberg <AndreasRossberg@web.de>:
> > "Chris King" < colanderman@gmail.com> wrote:
> > >
> > > # let create_foo () = object method foo (_: 'a) = () end;;
> > > val create_foo : unit -> < foo : 'a -> unit > = <fun>
> > > # let a = create_foo ();;
> > > val a : < bar : '_a -> unit > = <obj>
> > >
> > > the compiler determines a is monomorphic, since 'a is in a
> > > contravariant position.  But why, when 'a is placed in a covariant
> > > position:
> >
> > This has nothing to do with contravariance, nor with subtyping or
> objects at
> > all. What you observe is the infamous "value restriction": roughly, a
> > definition can only be polymorphic when its right-hand side is
> syntactically
> > a value (i.e. a function, tuple, constant, etc or combination thereof).
> In
> > your case it's an application.


This is Wright's value restriction, that is used in SML (maybe in
Alice ML too ?). OCaml
uses Garrigue's relaxed value restriction, which does care about variance
(see http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/morepoly-long.pdf<http://wwwfun.kurims.kyoto-u.ac.jp/%7Egarrigue/papers/morepoly-long.pdf>).
I haven't read that paper recently, but IIRC Garrigue's value restriction
allows generalisation of some of the type parameters that are in covariant
position.


Nope :
> # let f () = [];;
> val f : unit -> 'a list = <fun>
> # let x = f ();;
> val x : 'a list = []
>
> I have an application, but as it is covariant, the compiler lift the
> value restriction, and make it covariant. But for a reson I don't
> fully understood, one cannot do:
>
> # let f () (_ : 'a -> unit) = ();;
> val f : unit -> ('a -> unit) -> unit = <fun>
> # f ();;
> - : ('_a -> unit) -> unit = <fun>
>
> and have full polymorphism (when f() type is covariant).


IIRC, when binding to something that is not a value (like here, where the
toplevel output is bound to the application f()), type parameters that are
on the left of arrows are not generalized, regardless of variance; if the
type system allowed generalization of all covariant types it would lose its
principality property.

Note that
> this will work:
> # type +'a t = Foo of ((('a -> unit) -> unit));;
> type 'a t = Foo of (('a -> unit) -> unit)
> # let f () = Foo (fun _ -> ());;
> val f : unit -> 'a t = <fun>
> # f ();;
> - : 'a t = Foo <fun>
> (we have full polymorphisme here, with a code that is mostly
> equivalent to the first one, but not completely).


Maybe algebraic constructors are a special case of function application ?
After all, they can never "go wrong", can they ?

_______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 4957 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-02  7:03     ` Christophe Dehlinger
@ 2006-08-02  8:07       ` Andreas Rossberg
  0 siblings, 0 replies; 9+ messages in thread
From: Andreas Rossberg @ 2006-08-02  8:07 UTC (permalink / raw)
  To: O'Caml Mailing List

Christophe Dehlinger wrote:
>On 8/2/06, Remi Vanicat <remi.vanicat@gmail.com > wrote:
>>2006/8/1, Andreas Rossberg <AndreasRossberg@web.de>:
>>
>> This has nothing to do with contravariance, nor with subtyping or objects
at
>> all. What you observe is the infamous "value restriction": roughly, a
>> definition can only be polymorphic when its right-hand side is
syntactically
>> a value (i.e. a function, tuple, constant, etc or combination thereof).
In
>> your case it's an application.
>
>This is Wright's value restriction, that is used in SML (maybe in Alice ML
too ?).
>OCaml uses Garrigue's relaxed value restriction, which does care about
variance
>(see
http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/morepoly-long.pdf ).
>I haven't read that paper recently, but IIRC Garrigue's value restriction
allows
>generalisation of some of the type parameters that are in covariant
position.

Oops, right, somehow I had forgotten about the relaxation. Thanks to you and
Alain for the correction.

- Andreas


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-02  7:00     ` Alain Frisch
@ 2006-08-02 17:57       ` Chris King
  2006-08-04  2:42         ` Jacques Garrigue
  0 siblings, 1 reply; 9+ messages in thread
From: Chris King @ 2006-08-02 17:57 UTC (permalink / raw)
  To: Alain Frisch; +Cc: O'Caml Mailing List

On 8/2/06, Alain Frisch <Alain.Frisch@inria.fr> wrote:
> See the paper _Relaxing the value restriction_ by Jacques Garrigue (
> http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/morepoly-long.pdf
> ), page 15: dangerous type variables (which are not generalized when the
> right-hand side of the let-binding is not a value) are not only those is
> contravariant position - this would be enough to ensure type soundness -
> but also those which appear in a contravariant branch (e.g. anywhere on
> the left of an arrow) - this is necessary to ensure that the type system
> has principal types.

Okay, that (and Christophe's explanation) explains why hiding
everything in a module works.  Thanks everyone for your help!  It
seems I will have to use Obj.magic to get the type I want but at least
its use in this situation seems both safe and warranted.

- Chris


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-02 17:57       ` Chris King
@ 2006-08-04  2:42         ` Jacques Garrigue
  2006-08-04 14:18           ` Chris King
  0 siblings, 1 reply; 9+ messages in thread
From: Jacques Garrigue @ 2006-08-04  2:42 UTC (permalink / raw)
  To: colanderman; +Cc: caml-list

From: "Chris King" <colanderman@gmail.com>
> Okay, that (and Christophe's explanation) explains why hiding
> everything in a module works.  Thanks everyone for your help!  It
> seems I will have to use Obj.magic to get the type I want but at least
> its use in this situation seems both safe and warranted.

There are no "safe" uses of Obj.magic. It just happens to work in some
cases, but it is strongly discouraged to use it to get around the type
system, particularly when there are other ways to reach the same
result.

type 'a bar_t = Bar of <bar: ('a -> unit) -> unit> ;;
let create_bar () = Bar (object method bar (_: 'a) = () end);;
let b = create_bar ();;
let Bar b = b;;

Note that you need two definitions, as mixing the application with the
extraction would loose the polymorphism.
If you still want to use Obj.magic, remember to put complete type
annotions on both its input and output, as the lack of type
information may break the compiler.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Unexpected '_a problem
  2006-08-04  2:42         ` Jacques Garrigue
@ 2006-08-04 14:18           ` Chris King
  0 siblings, 0 replies; 9+ messages in thread
From: Chris King @ 2006-08-04 14:18 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

On 8/3/06, Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> wrote:
> type 'a bar_t = Bar of <bar: ('a -> unit) -> unit> ;;
> let create_bar () = Bar (object method bar (_: 'a) = () end);;
> let b = create_bar ();;
> let Bar b = b;;

Okay, that got the types to work out correctly.

> If you still want to use Obj.magic, remember to put complete type
> annotions on both its input and output, as the lack of type
> information may break the compiler.

Surprisingly putting a type annotation on its output caused it to
infer a monomorphic type - I was relying on the type in the module's
signature since the type there is abstract.


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-08-04 14:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-08-01 20:47 Unexpected '_a problem Chris King
2006-08-01 21:20 ` [Caml-list] " Andreas Rossberg
2006-08-01 22:09   ` Remi Vanicat
2006-08-02  7:00     ` Alain Frisch
2006-08-02 17:57       ` Chris King
2006-08-04  2:42         ` Jacques Garrigue
2006-08-04 14:18           ` Chris King
2006-08-02  7:03     ` Christophe Dehlinger
2006-08-02  8:07       ` Andreas Rossberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).