caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Mixing variant types...
@ 2006-01-11  9:56 Jonathan Roewen
  0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Roewen @ 2006-01-11  9:56 UTC (permalink / raw)
  To: caml-list

Hi,

I'm wondering why the following doesn't work:

let sources = (Event.receive internal_control) :: List.map (fun w ->
Channel.receive w.control) !windows in

where internal_control passes a (window,`New_window) event over the
channel, and w.control passes values of the type (window,event), where
type event = [ `Repaint ].

I thought that since they're both variant types, I should be able to
build a list that uses both variants.

Hmm, I just had a thought: is this because it's a tuple with the
variant inside the tuple?

Jonathan


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

* Re: [Caml-list] Mixing variant types...
  2006-01-13  7:56         ` skaller
@ 2006-01-13  9:37           ` Jacques Garrigue
  0 siblings, 0 replies; 10+ messages in thread
From: Jacques Garrigue @ 2006-01-13  9:37 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

From: skaller <skaller@users.sourceforge.net>

> And if I'm right, the + in the implementation proves covariance
> mechanically so it should be safe.

As the Event module does not use unsafe features, this indeed proves
correctness. 

> Should I add a feature request to the bug tracker?

No need: this is already fixed.

   Jacques


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

* Re: [Caml-list] Mixing variant types...
  2006-01-13  4:57       ` Jacques Garrigue
@ 2006-01-13  7:56         ` skaller
  2006-01-13  9:37           ` Jacques Garrigue
  0 siblings, 1 reply; 10+ messages in thread
From: skaller @ 2006-01-13  7:56 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

On Fri, 2006-01-13 at 13:57 +0900, Jacques Garrigue wrote:
> From: skaller <skaller@users.sourceforge.net>
>> (* event.ml *)
>> type +'a event =
>>     Communication of 'a behavior
>>   | Choose of 'a event list
>>   | WrapAbort of 'a event * (unit -> unit)
>>   | Guard of (unit -> 'a event)

> The + above is not needed (it is implied by the definition)

But it would fail if the type is not in fact covariant
in its argument?

> You still need to coerce the resulting list:
> (List.map (fun w -> receive w.control) !windows :> ws_event list)

Still doesn't seem to work: OUCH! Yes it DOES. Argg..
I modified

otherlibs/threads/event.*

but I didn't modify

otherlibs/systhreads/event.*

So when I compile with -thread it doesn't work.
But when I compile with -vmthread it does work.
Which is pretty conclusive proof the patch does work
in at least one case. And if I'm right, the + in 
the implementation proves covariance mechanically so
it should be safe.

Should I add a feature request to the bug tracker?

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


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

* Re: [Caml-list] Mixing variant types...
  2006-01-12  3:57     ` skaller
@ 2006-01-13  4:57       ` Jacques Garrigue
  2006-01-13  7:56         ` skaller
  0 siblings, 1 reply; 10+ messages in thread
From: Jacques Garrigue @ 2006-01-13  4:57 UTC (permalink / raw)
  To: skaller; +Cc: jonathan.roewen, caml-list

From: skaller <skaller@users.sourceforge.net>

> I just tried making Event.event covariant but it didn't seem to work,
> perhaps I did something wrong here?
> 
> (* event.ml *)
> type +'a event =
>     Communication of 'a behavior
>   | Choose of 'a event list
>   | WrapAbort of 'a event * (unit -> unit)
>   | Guard of (unit -> 'a event)

The + above is not needed (it is implied by the definition)

> (* event.mli *)
> type +'a event

That + is sufficient.

> Rebuilt and reinstalled Ocaml 3.09.0 ..  changed example to:
> 
>       List.map (fun w ->
>         (* Event.wrap (receive w.control) (fun (w,e) -> w, (e:> ec)) *)
>          (receive w.control) 
>       )
>       [] (* !windows .. *)
> 
> eliminating the Event.wrap and hoping this would fix it .. 
> 
> skaller@rosella:/work/felix/flx$ ocamlc -thread r.ml
> File "r.ml", line 28, characters 6-143:
> This expression has type (window * event) Event.event list
> but is here used with type ws_event list
> Type (window * event) Event.event is not compatible with type
>   ws_event = (window * ec) Event.event
> Type event = [ `Repaint ] is not compatible with type
>   ec = [ `New_window | `Repaint ]
> The first variant type does not allow tag(s) `New_window

You still need to coerce the resulting list:
(List.map (fun w -> receive w.control) !windows :> ws_event list)

Jacques


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

* Re: [Caml-list] Mixing variant types...
  2006-01-12  3:22   ` Jacques Garrigue
  2006-01-12  3:57     ` skaller
@ 2006-01-12  3:59     ` Jonathan Roewen
  1 sibling, 0 replies; 10+ messages in thread
From: Jonathan Roewen @ 2006-01-12  3:59 UTC (permalink / raw)
  Cc: caml-list

This explains it a bit thanks. These variant types have some strange
properties ;-) And using wrap certainly fixed it.

Thanks guys =)


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

* Re: [Caml-list] Mixing variant types...
  2006-01-12  3:22   ` Jacques Garrigue
@ 2006-01-12  3:57     ` skaller
  2006-01-13  4:57       ` Jacques Garrigue
  2006-01-12  3:59     ` Jonathan Roewen
  1 sibling, 1 reply; 10+ messages in thread
From: skaller @ 2006-01-12  3:57 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: jonathan.roewen, caml-list

On Thu, 2006-01-12 at 12:22 +0900, Jacques Garrigue wrote:

> You can already simulate subtyping using Event.wrap:
>   Event.wrap e (fun x -> (x : t1 :> t2))
> will turn a t1 event into a t2 event.
> (So this probably means that Event.event should be covariant to start
> with...)
> 
> For practical applications, the solution suggested by skaller might be
> satisfactory too.

Err .. but my solution does use Event.wrap .. :

        Event.wrap (receive w.control) (fun (w,e) -> w, (e:> ec))

I just tried making Event.event covariant but it didn't seem to work,
perhaps I did something wrong here?

(* event.ml *)
type +'a event =
    Communication of 'a behavior
  | Choose of 'a event list
  | WrapAbort of 'a event * (unit -> unit)
  | Guard of (unit -> 'a event)

(* event.mli *)
type +'a event

Rebuilt and reinstalled Ocaml 3.09.0 ..  changed example to:

      List.map (fun w ->
        (* Event.wrap (receive w.control) (fun (w,e) -> w, (e:> ec)) *)
         (receive w.control) 
      )
      [] (* !windows .. *)

eliminating the Event.wrap and hoping this would fix it .. 

skaller@rosella:/work/felix/flx$ ocamlc -thread r.ml
File "r.ml", line 28, characters 6-143:
This expression has type (window * event) Event.event list
but is here used with type ws_event list
Type (window * event) Event.event is not compatible with type
  ws_event = (window * ec) Event.event
Type event = [ `Repaint ] is not compatible with type
  ec = [ `New_window | `Repaint ]
The first variant type does not allow tag(s) `New_window

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


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

* Re: [Caml-list] Mixing variant types...
  2006-01-12  1:24 ` Jonathan Roewen
  2006-01-12  2:45   ` skaller
@ 2006-01-12  3:22   ` Jacques Garrigue
  2006-01-12  3:57     ` skaller
  2006-01-12  3:59     ` Jonathan Roewen
  1 sibling, 2 replies; 10+ messages in thread
From: Jacques Garrigue @ 2006-01-12  3:22 UTC (permalink / raw)
  To: jonathan.roewen; +Cc: caml-list

From: Jonathan Roewen <jonathan.roewen@gmail.com>

> File "window_system.ml", line 99, characters 23-50:
> This expression cannot be coerced to type
>   ws_event = (window * [ `New_window | `Repaint ]) Event.event;
> it has type (window * event) Event.event but is here used with type
>   ws_event = (window * [ `New_window | `Repaint ]) Event.event
> Type event = [ `Repaint ] is not compatible with type
>   [ `New_window | `Repaint ]
> The first variant type does not allow tag(s) `New_window
> 
> The toplevel has just proven to me that this can be done, so I don't
> understand what's going on here.

The reason is simple: Event.event is not marked ascovariant in its
parameter. So even if t1 is a subtype of t2, this does not imply that
t1 Event.event will be a subtype of t2 Event.event.
After thinking a bit of the semantics, it seems that it would be safe
to make Event.event covariant. Of course Event.channel cannot be
made covariant, as it can be used both to send and receive values.

You can already simulate subtyping using Event.wrap:
  Event.wrap e (fun x -> (x : t1 :> t2))
will turn a t1 event into a t2 event.
(So this probably means that Event.event should be covariant to start
with...)

For practical applications, the solution suggested by skaller might be
satisfactory too.

Jacques


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

* Re: [Caml-list] Mixing variant types...
  2006-01-12  1:24 ` Jonathan Roewen
@ 2006-01-12  2:45   ` skaller
  2006-01-12  3:22   ` Jacques Garrigue
  1 sibling, 0 replies; 10+ messages in thread
From: skaller @ 2006-01-12  2:45 UTC (permalink / raw)
  To: Jonathan Roewen; +Cc: caml-list

On Thu, 2006-01-12 at 14:24 +1300, Jonathan Roewen wrote:

> So, it all works fine & dandy. So I'm trying to duplicate this with my
> window system problem.

[ .. ]

Try this:


(* Module Channel *)
type ('a,'b) channel = {
        source: 'a;
        chan: ('a * 'b) Event.channel;
}

let send channel value = Event.send channel.chan (channel.source, value)

let receive channel = Event.receive channel.chan

(* Module Window_system *)
type event = [ `Repaint ]
type control = [ `New_window ]
type ec = [ event | control ]
type window = {
        control: (window, event) channel;
}

type ws_event = (window * ec) Event.event


let run () =
  let internal_control = Event.new_channel ()  in
  while true do
    let sources =
      ((Event.receive internal_control) :> ws_event) ::
      List.map (fun w ->
        Event.wrap (receive w.control) (fun (w,e) -> w, (e:> ec))
      )
      [] (* !windows .. *)
    in
    match Event.select sources with
    | (source, `Repaint) -> () (* repaint source *)
    | _ -> ()
  done

;;


-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


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

* Re: [Caml-list] Mixing variant types...
  2006-01-11 10:36 Jonathan Roewen
@ 2006-01-12  1:24 ` Jonathan Roewen
  2006-01-12  2:45   ` skaller
  2006-01-12  3:22   ` Jacques Garrigue
  0 siblings, 2 replies; 10+ messages in thread
From: Jonathan Roewen @ 2006-01-12  1:24 UTC (permalink / raw)
  Cc: caml-list

I've played with coercing to a wider type in the toplevel, and the
following works fine:

# type a = [ `Repaint ];;
type a = [ `Repaint ]
# type b = [ `New_window ];;
type b = [ `New_window ]
# let f () : a = `Repaint;;
val f : unit -> a = <fun>
# let g () : b = `New_window;;
val g : unit -> b = <fun>
# let l = [ (f :> (unit -> [`Repaint|`New_window])); (g :> (unit ->
[`Repaint|`New_window]))];;
val l : (unit -> [ `New_window | `Repaint ]) list = [<fun>; <fun>]
# List.map (fun f -> f ()) l;;
- : [ `New_window | `Repaint ] list = [`Repaint; `New_window]
# let ll = [ ((f ()) :> [`Repaint|`New_window]); ((g ()) :> [a|b]) ];;
val ll : [ `New_window | `Repaint ] list = [`Repaint; `New_window]

So, it all works fine & dandy. So I'm trying to duplicate this with my
window system problem.

I have:

(* Module Channel *)
type ('a,'b) channel = {
	source: 'a;
	chan: ('a * 'b) Event.channel;
}

let send channel value = Event.send channel.chan (channel.source, value)

let receive channel = Event.receive channel.chan

(* Module Window_system *)
type event = [ `Repaint ]
type control = [ `New_window ]
type window = {
	mutable bounds: bounds;
	
	surface: Cairo.image_surface;
	
	mutable clips: bounds list;
	
	control: (window, event) Channel.channel;
}

type ws_event = (window * [event | control]) Event.event

let create left top width height =
  let rec window = {
    ...
    control = { source = window; chan = Event.new_channel (); };
  }

let run () =
  while true do
    let sources =
      ((Event.receive internal_control) :> ws_event) ::
      List.map (fun w -> ((Channel.receive w.control) :> ws_event))
!windows in (* Line 99 *)
    match Event.select sources with
    | source, `Repaint -> repaint source
    | _ -> ()
  done

And I get the following error:

File "window_system.ml", line 99, characters 23-50:
This expression cannot be coerced to type
  ws_event = (window * [ `New_window | `Repaint ]) Event.event;
it has type (window * event) Event.event but is here used with type
  ws_event = (window * [ `New_window | `Repaint ]) Event.event
Type event = [ `Repaint ] is not compatible with type
  [ `New_window | `Repaint ]
The first variant type does not allow tag(s) `New_window

The toplevel has just proven to me that this can be done, so I don't
understand what's going on here.

Kindest Regards,

Jonathan Roewen


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

* Re: [Caml-list] Mixing variant types...
@ 2006-01-11 10:36 Jonathan Roewen
  2006-01-12  1:24 ` Jonathan Roewen
  0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Roewen @ 2006-01-11 10:36 UTC (permalink / raw)
  To: Christophe Dehlinger; +Cc: caml-list

> Hi,
>
> Have you tried explicitly casting event to an open variant type (or
> whatever they're called) ?
>
> let sources = (Event.receive internal_control) :: List.map (fun w ->
> Channel.receive (w.control :> 'a * [> event ]) !windows in

Hmm, I tried that, and also:

let sources = (Event.receive internal_control) :: List.map (fun w ->
((Channel.receive w.control) :> (window * [> event | `New_window ])
Event.event)) !windows in

I now get:

This expression cannot be coerced to type
  (window * ([> `New_window | `Repaint ] as 'a)) Event.event;
it has type (window * event) Event.event but is here used with type
  (window * 'a) Event.event
Type event = [ `Repaint ] is not compatible with type 'a
The first variant type does not allow tag(s) `New_window

Jonathan


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

end of thread, other threads:[~2006-01-13  9:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-11  9:56 [Caml-list] Mixing variant types Jonathan Roewen
2006-01-11 10:36 Jonathan Roewen
2006-01-12  1:24 ` Jonathan Roewen
2006-01-12  2:45   ` skaller
2006-01-12  3:22   ` Jacques Garrigue
2006-01-12  3:57     ` skaller
2006-01-13  4:57       ` Jacques Garrigue
2006-01-13  7:56         ` skaller
2006-01-13  9:37           ` Jacques Garrigue
2006-01-12  3:59     ` Jonathan Roewen

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).