* [Caml-list] writing a not too simple parametrized class interface
@ 2011-01-14 17:46 Philippe Strauss
2011-01-15 0:53 ` Jeremy Yallop
2011-01-15 1:00 ` Jacques Garrigue
0 siblings, 2 replies; 3+ messages in thread
From: Philippe Strauss @ 2011-01-14 17:46 UTC (permalink / raw)
To: caml-list
Hello ocaml users,
I'm in a fight with hindley-milner when writing a .mli for a set of classes which implement a pipeline pattern, for processing either float array or Complex.t array, caching the result in each pipeline element.
each element type (class) inherit from node_virt_t, which use parametrized type for circumventing around the lack of "c++" like method overloading, for having the ability to use either float array or Complex.t array as input/output data type.
the whole things works perfectly, but the .mli seems not easy to write.
uncomment class node_spectrum_t or class node_mag_t and you'll get:
File "nodes.mli", line 68, characters 30-45:
Error: The type parameter Complex.t array
does not meet its constraint: it should be float array
which I don't understand.
thanks for any advice.
--8<-- nodes.mli :
type node_parameters_t = Spectrum | Mag | Magn | Smooth | Fade | Eqmp | Power | Trim
class type parameters_t =
object
val mutable len : int
val mutable hlen : int
val mutable sf : int
val mutable chan : int
val mutable f_half : float array
val mutable f_log : float array
val mutable fls : float
val mutable fln : float
val mutable fhn : float
val mutable nth : float
val mutable fll : float
val mutable flh : float
val mutable fhl : float
val mutable fhh : float
val mutable th_before : float
val mutable th_after : float
method set_len_sf : int -> int -> unit
method get_len : int
method get_hlen : int
method get_sf : int
method get_f_half : float array
method get_f_log : float array
method get_chan : int
method set_chan : int -> unit
method get_fln : float
method set_fln : float -> unit
method get_fhn : float
method set_fhn : float -> unit
method get_fls : float
method set_fls : float -> unit
method get_nth : float
method set_nth : float -> unit
method get_fade_freq : float * float * float * float
method set_fade_freqs : float * float * float * float -> unit
method get_th_before : float
method set_th_before : float -> unit
method get_th_after : float
method set_th_after : float -> unit
method get_parh : node_parameters_t -> string
end
class node_head_t : float array array ->
object
val impulses : float array array
method get : int -> int * int * float array
end
class virtual ['b, 'c] node_virt_t : ('a, 'b) node_virt_t -> parameters_t -> int -> int ->
object
val previous : ('a, 'b) node_virt_t
val parms : parameters_t
val hres : (int * int * string, 'c) Hashtbl.t
val mutable id : int array
method get_id : int -> int
method private inc_id : int -> unit
method virtual ptyp : unit -> node_parameters_t
method virtual process : 'b -> 'c
method private pstore : int -> int * int * 'c
method get : int -> int * int * 'c
end
(* class node_spectrum_t : node_head_t -> parameters_t -> int -> int ->
object
inherit [float array, Complex.t array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : float array -> Complex.t array
end *)
(* class node_mag_t : (Complex.t array, float array) node_virt_t -> parameters_t -> int -> int ->
object
inherit [Complex.t array, float array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : Complex.t array -> float array
end *)
(* class node_magnormalize_t : (float array, float array) node_virt_t -> parameters_t -> int -> int ->
object
inherit [float array, float array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : float array -> float array
end *)
(* class node_smooth_t : (float array, float array) node_virt_t -> parameters_t -> int -> int ->
object
inherit [float array, float array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : float array -> float array
end *)
(* class node_fade_t : (float array, float array) node_virt_t -> parameters_t -> int -> int ->
object
inherit [float array, float array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : float array -> float array
end *)
(* class node_eqminphase_t : (float array, float array) node_virt_t -> parameters_t -> int -> int ->
object
inherit [float array, float array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : float array -> float array
end *)
(* class node_power_t : (float array, float array) node_virt_t -> parameters_t -> int -> int ->
object
inherit [float array, float array] node_virt_t
method ptyp : unit -> node_parameters_t
method process : float array -> float array
end *)
(* class node_trim_t : (float array, float array) node_virt_t -> (float array, float array) node_virt_t -> parameters_t ->
object
val nd_eqmp : (float array, float array) node_virt_t
val nd_powm : (float array, float array) node_virt_t
val parms : parameters_t
method ptyp : unit -> node_parameters_t
method make_coeffs : unit
end *)
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Caml-list] writing a not too simple parametrized class interface
2011-01-14 17:46 [Caml-list] writing a not too simple parametrized class interface Philippe Strauss
@ 2011-01-15 0:53 ` Jeremy Yallop
2011-01-15 1:00 ` Jacques Garrigue
1 sibling, 0 replies; 3+ messages in thread
From: Jeremy Yallop @ 2011-01-15 0:53 UTC (permalink / raw)
To: Philippe Strauss; +Cc: caml-list
On 14 January 2011 17:46, Philippe Strauss <philou@philou.ch> wrote:
> the whole things works perfectly, but the .mli seems not easy to write.
It can be useful in such circumstances to ask ocamlc to print out an
interface (.mli) for you. Once you've written your implementation
(nodes.ml), you can run
ocamlc -i nodes.ml
to dump the interface inferred by OCaml. The result is not always a
good starting point for your actual interface file, since any
structural types such as objects (or polymorphic variants) will be
expanded in full, and will not reflect the inheritance (or variant
extension) that you used in your code. Still, it can be helpful for
debugging.
You can also use ocamlc in this way with interface files as input, and
this turns out to be helpful in diagnosing your problem here. Running
ocamlc -i nodes.mli
on your code gives the following output for node_virt_t (in amongst
the other class types):
class virtual ['a, 'b] node_virt_t :
('a, 'a) node_virt_t ->
parameters_t ->
int ->
int ->
object
constraint 'b = 'a
val hres : (int * int * string, 'a) Hashtbl.t
val mutable id : int array
val parms : parameters_t
val previous : ('a, 'a) node_virt_t
method get : int -> int * int * 'a
method get_id : int -> int
method private inc_id : int -> unit
method virtual process : 'a -> 'a
method private pstore : int -> int * int * 'a
method virtual ptyp : unit -> node_parameters_t
end
If you compare this with your original type, you'll notice that all
your type variables have been unified: you wrote
class virtual ['b, 'c] node_virt_t : ('a, 'b) node_virt_t -> ...
but ocamlc has changed this to
class virtual ['a, 'b] node_virt_t : ('a, 'a) node_virt_t -> ...
and added a further constraint on the class parameters:
constraint 'b = 'a
This has happened because you've used type variables inconsistently in
the type of node_virt_t: you've given it parameters 'b and 'c, but
used 'a, 'b and 'c to the right of the colon.
The following type for node_virt_t uses 'a and 'b more consistently,
and may more closely reflect your intentions:
class virtual ['a, 'b] node_virt_t :
('a, 'b) node_virt_t ->
parameters_t ->
int ->
int ->
object
val previous : ('a, 'b) node_virt_t
val parms : parameters_t
val hres : (int * int * string, 'b) Hashtbl.t
val mutable id : int array
method get_id : int -> int
method private inc_id : int -> unit
method virtual ptyp : unit -> node_parameters_t
method virtual process : 'a -> 'b
method private pstore : int -> int * int * 'b
method get : int -> int * int * 'b
end
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Caml-list] writing a not too simple parametrized class interface
2011-01-14 17:46 [Caml-list] writing a not too simple parametrized class interface Philippe Strauss
2011-01-15 0:53 ` Jeremy Yallop
@ 2011-01-15 1:00 ` Jacques Garrigue
1 sibling, 0 replies; 3+ messages in thread
From: Jacques Garrigue @ 2011-01-15 1:00 UTC (permalink / raw)
To: Philippe Strauss; +Cc: caml-list
On 2011/01/15, at 2:46, Philippe Strauss wrote:
> Hello ocaml users,
>
> I'm in a fight with hindley-milner when writing a .mli for a set of classes which implement a pipeline pattern, for processing either float array or Complex.t array, caching the result in each pipeline element.
>
> each element type (class) inherit from node_virt_t, which use parametrized type for circumventing around the lack of "c++" like method overloading, for having the ability to use either float array or Complex.t array as input/output data type.
>
> the whole things works perfectly, but the .mli seems not easy to write.
> uncomment class node_spectrum_t or class node_mag_t and you'll get:
>
> File "nodes.mli", line 68, characters 30-45:
> Error: The type parameter Complex.t array
> does not meet its constraint: it should be float array
>
> which I don't understand.
[...]
The problem can be tracked down to this single line:
> class virtual ['b, 'c] node_virt_t : ('a, 'b) node_virt_t -> parameters_t -> int -> int -> [...]
Object types are allowed to be recursive, but they are restricted to _regular_ types,
where recursive occurences have identical type parameters.
In particular, this means that in the above line, ('a,'b) node_virt_t and ('b,'c) node_virt_t
must have the same parameters, i.e. that 'a = 'b and 'b = 'c, i.e. all your types
end up being identical.
But in your particular case, the recursion seems unnecessary.
You could write:
class type ['b, 'c] node_t :
object
method get_id : int -> int
method private inc_id : int -> unit
method virtual ptyp : unit -> node_parameters_t
method virtual process : 'b -> 'c
method private pstore : int -> int * int * 'c
method get : int -> int * int * 'c
end
class virtual ['b, 'c] node_virt_t : ('a, 'b) node_t -> parameters_t -> int -> int ->
object
val previous : ('a, 'b) node_t
val parms : parameters_t
val hres : (int * int * string, 'c) Hashtbl.t
val mutable id : int array
inherit ['b,'c] node_t
end
Hopefully, this should solve your typing problem.
Of course, you might also consider whether you really need to use objects for that.
Closures are usually enough for cacheing, and they do not involve the advanced
aspects of the type system.
Jacques Garrigue
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-01-15 1:00 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-14 17:46 [Caml-list] writing a not too simple parametrized class interface Philippe Strauss
2011-01-15 0:53 ` Jeremy Yallop
2011-01-15 1:00 ` Jacques Garrigue
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox