caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [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;
as well as URLs for NNTP newsgroup(s).