>From the ocaml reference docs:
# let bar_of_foo t = (t : foo :> bar);;
val bar_of_foo : foo -> bar = <fun>
# g (bar_of_foo c);;
- : bar = `Tree (`Tree `Nil)
Jonathan
_______________________________________________
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
I should've added that without needing an intermediate function, you
can also do:
g (c : foo :> bar);;
let f (x : foo) : bar = match x with
| `A -> `D
| `B _ | `C _ as x -> (x : bar)
Only thing I could think of was:
# let rec occurs i = function
| `A j -> i = j
| `C (f,b) -> (occurs_foo i f) || (occurs_bar i b)
| otherwise -> false
and occurs_foo i = function
| `A j -> i = j
| otherwise -> false
and occurs_bar i = function
| `A j -> i = j
| `C (f,b) -> (occurs_foo i f) || (occurs_bar i b)
| otherwise -> false;;
val occurs :
'a ->
[> `A of 'a
| `C of ([> `A of 'a ] as 'b) * ([> `A of 'a | `C of 'b * 'c ] as 'c) ] ->
bool = <fun>
val occurs_foo : 'a -> [> `A of 'a ] -> bool = <fun>
val occurs_bar :
'a -> ([> `A of 'a | `C of [> `A of 'a ] * 'b ] as 'b) -> bool = <fun>
# occurs 2 (`C ((`D (`B)), (`C (`A 3, (`D (`C (`A 4, `A 2)))))));;
- : bool = false
Basically specialising on the two types. There may be a way to coerce
them to not need it, but I'm not sure what it is.
Here are two other solutions:
# let rec occurs i x =
let map = function
| `A j -> `A j
| `C (f,b) -> print_endline "C"; `C (f,b)
| x -> `None
in match map x with
| `A j -> i = j
| `None -> false
| `C (f,b) -> (occurs i f) or (occurs i b);;
val occurs : 'a -> ([> `A of 'a | `C of 'b * 'b ] as 'b) -> bool = <fun>
--
# let occurs i x =
let map = function
| `A _ | `C (_,_) as x -> x | _ -> `None
in
let rec occurs = function
| `A j -> i = j
| `C (f,b) -> (occurs (map f)) or (occurs (map b))
| `None -> false
in occurs x;;
val occurs :
'a ->
[ `A of 'a
| `C of
([> `A of 'a | `C of 'b * ([> `A of 'a | `C of 'b * 'c ] as 'c) ] as 'b) *
'c
| `None ] -> bool = <fun>
Pretty damn ugly! But it works... Perhaps someone more proficient with
variant types on the list can come up with a more reasonable solution
than my hack ;-)
As long as foo and bar are two subtypes of a common type, you can
still solve the problem by defining that type and using subtyping:
type foobar = [`A of int | `B | `C of foobar * foobar | `D of foobar]
let occurs_foo i x = occurs i (x : foo :> foobar)
let occurs_bar i x = occurs i (x : bar :> foobar)
Jacques Garrigue
Rich.
----------------------------------------------------------------------
type colour = [ `Red | `Green | `Blue ]
type colour' = [ colour | `Default ]
type instructions = Set_foreground of colour' | Set_background of colour'
let default_fg : colour = `Red
let default_bg : colour = `Green
let process_instructions =
List.fold_left (
fun (fg, bg) ->
function
| Set_foreground `Default ->
let new_fg = default_fg in
(new_fg, bg)
| Set_foreground new_fg ->
(new_fg, bg)
| Set_background `Default ->
let new_bg = default_bg in
(fg, new_bg)
| Set_background new_bg ->
(fg, new_bg)
)
let string_of_colour = function
| `Red -> "red"
| `Green -> "green"
| `Blue -> "blue"
let () =
let instrs =
[ Set_foreground `Blue; Set_background `Red; Set_foreground `Default ] in
let fg, bg = `Green, `Blue in
let fg, bg = process_instructions (fg, bg) instrs in
print_endline ("fg = " ^ string_of_colour fg);
print_endline ("bg = " ^ string_of_colour bg)
----------------------------------------------------------------------
--
Richard Jones, CTO Merjis Ltd.
Merjis - web marketing and technology - http://merjis.com
Team Notepad - intranets and extranets for business - http://team-notepad.com
You just need some type constraints so it knows you're starting with a
colour pair, not a colour' pair:
let process_instructions (initial:colour * colour) =
List.fold_left (
fun (fg, bg) ->
function
| Set_foreground `Default ->
let new_fg = default_fg in
(new_fg, bg)
| Set_foreground (#colour as new_fg) ->
(new_fg, bg)
| Set_background `Default ->
let new_bg = default_bg in
(fg, new_bg)
| Set_background (#colour as new_bg) ->
(fg, new_bg)
) initial
Jonathan
Thanks - that's exactly the syntax I was looking for.
Rich.
I seem to be running into the problem of not being able to coerce
polymorphic abstract types that use variants.
Eg:
type 'a t;;
type x = [ `Foo ];;
type y = [ `Bar | x ];;
let widen x = (x : x t :> y t);;
Gives:
Type x t is not a subtype of type y t
Type x = [ `Foo ] is not compatible with type y = [ `Bar | `Foo ]
The first variant type does not allow tag(s) `Bar
Yet the above approach works fine for non-abstract types.
Jonathan
You need to explicitly specify the variance of 'a t:
type +'a t;;
This tells the type system that t is covariant with respect to 'a: if
x is a subtype of y, then x t is a subtype of y t. Not all compound
types share this property (most notably, mutable structures are
invariant and function arguments are contravariant) so O'Caml must
assume all abstract types to be invariant unless it's told otherwise.