* [Caml-list] Arrays and private types
@ 2012-03-14 20:12 Pietro Abate
2012-03-14 23:00 ` Gabriel Scherer
0 siblings, 1 reply; 4+ messages in thread
From: Pietro Abate @ 2012-03-14 20:12 UTC (permalink / raw)
To: caml-list
hello world.
In my application I'm using arrays all over, and lately I've discovered a
couple of bugs related to the fact that I was using the index of one array to
get the element of another array. Since both indexes are int the compiler could
not help me at all. Using private types it seems I can solve this problem
without loosing anything (??).
This is what I came up with ... and since, I was at it I've also restricted
the type of the Array...
my questions are :
- Is there a better way of doing it, such that the type of IntArray is not
IntArray.T.t array but rather int array ?
Consider that I'm going to this deal of trouble only because I want to define
the Array signature (with the private annotation) only once and not for each
type of array I want to instantiate ...
- how can avoid this problem ?
# let a = IntArray.make 10 0 ;;
val a : IntArray.T.t array = [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
# a.(1);;
- : IntArray.T.t = 0
#
# IntArray.get a 1 ;;
Error: This expression has type int but an expression was expected of type
IntArray.t
Ideally I'd like the same type of error when using a.(1) ...
thanks
pietro
-------------------
module type T = sig type t end
module MakePrivateArraySig (T : T) = struct
module type Sig = sig
type t = private int
val of_int : int -> t
val to_int : t -> int
val length : T.t array -> int
val get : T.t array -> t -> T.t
val set : T.t array -> t -> T.t -> unit
val make : int -> T.t -> T.t array
val create : int -> T.t -> T.t array
val init : int -> (t -> T.t) -> T.t array
val append : T.t array -> T.t array -> T.t array
val concat : T.t array list -> T.t array
val to_list : T.t array -> T.t list
val of_list : T.t list -> T.t array
val iter : (T.t -> unit) -> T.t array -> unit
val map : (T.t -> 'b) -> T.t array -> 'b array
val iteri : (t -> T.t -> unit) -> T.t array -> unit
val mapi : (t -> T.t -> 'b) -> T.t array -> 'b array
val fold_left : (T.t -> 'b -> T.t) -> T.t -> 'b array -> T.t
val fold_right : (T.t -> 'b -> 'b) -> T.t array -> 'b -> 'b
val unsafe_get : T.t array -> int -> T.t
val unsafe_set : T.t array -> int -> T.t -> unit
end
end
module type IntArrayType = sig
module T : sig type t = int end
include MakePrivateArraySig(T).Sig
end
module type FloatArrayType = sig
module T : sig type t = float end
include MakePrivateArraySig(T).Sig
end
module IntArray : IntArrayType = struct
type t = int
module T = struct type t = int end
include Array
let of_int x = x
let to_int x = x
end
module FloatArray : FloatArrayType = struct
type t = int
module T = struct type t = float end
include Array
let of_int x = x
let to_int x = x
end
-----------------------
This is clearly the solution for the first question, but I'll be forced to
write a signature for each array ... I "feel" that there is a clean way of
doing this ...
-----------------------
module StringArray : Sig = struct
type t = int
include Array
let of_int x = x
let to_int x = x
end
;;
module type Sig =
sig
type t = private int
val of_int : int -> t
val to_int : t -> int
val length : string array -> int
val get : string array -> t -> string
val set : string array -> t -> string -> unit
val make : int -> string -> string array
val create : int -> string -> string array
val init : int -> (t -> string) -> string array
val append : string array -> string array -> string array
val concat : string array list -> string array
val to_list : string array -> string list
val of_list : string list -> string array
val iter : (string -> unit) -> string array -> unit
val map : (string -> 'a) -> string array -> 'a array
val iteri : (t -> string -> unit) -> string array -> unit
val mapi : (t -> string -> 'a) -> string array -> 'a array
val fold_left : (string -> 'a -> string) -> string -> 'a array -> string
val fold_right : (string -> 'a -> 'a) -> string array -> 'a -> 'a
val unsafe_get : string array -> int -> string
val unsafe_set : string array -> int -> string -> unit
end
# let c = StringArray.make 10 "a";;
val c : string array = [|"a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"|]
# StringArray.set c 1 "aa";;
Error: This expression has type int but an expression was expected of type
StringArray.t
# StringArray.set c (StringArray.of_int 1) "aa";;
- : unit = ()
# c;;
- : string array = [|"a"; "aa"; "a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"|]
#
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Caml-list] Arrays and private types
2012-03-14 20:12 [Caml-list] Arrays and private types Pietro Abate
@ 2012-03-14 23:00 ` Gabriel Scherer
2012-03-15 11:04 ` Pietro Abate
0 siblings, 1 reply; 4+ messages in thread
From: Gabriel Scherer @ 2012-03-14 23:00 UTC (permalink / raw)
To: Pietro Abate; +Cc: caml-list
Here is a proposal:
https://gitorious.org/gasche-snippets/private-array-keys-type/blobs/master/private_array_key_types.ml
It works by using a functor to generate "fresh" private types for
keys. Note that the arrays themselves are still polymorphic (no
IntArray FloatArray etc.). The user still has to use the discipline to
produce a new application of ArrayMake each time she wants to use a
different kind of array: if she only does `module A = ArrayMake(struct
end)` and then use `A` for everything, there will be no additional
safety guarantee.
On Wed, Mar 14, 2012 at 9:12 PM, Pietro Abate
<Pietro.Abate@pps.jussieu.fr> wrote:
> hello world.
>
> In my application I'm using arrays all over, and lately I've discovered a
> couple of bugs related to the fact that I was using the index of one array to
> get the element of another array. Since both indexes are int the compiler could
> not help me at all. Using private types it seems I can solve this problem
> without loosing anything (??).
>
> This is what I came up with ... and since, I was at it I've also restricted
> the type of the Array...
>
> my questions are :
>
> - Is there a better way of doing it, such that the type of IntArray is not
> IntArray.T.t array but rather int array ?
> Consider that I'm going to this deal of trouble only because I want to define
> the Array signature (with the private annotation) only once and not for each
> type of array I want to instantiate ...
>
> - how can avoid this problem ?
> # let a = IntArray.make 10 0 ;;
> val a : IntArray.T.t array = [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
> # a.(1);;
> - : IntArray.T.t = 0
> #
> # IntArray.get a 1 ;;
> Error: This expression has type int but an expression was expected of type
> IntArray.t
>
> Ideally I'd like the same type of error when using a.(1) ...
>
>
> thanks
> pietro
>
> -------------------
>
> module type T = sig type t end
>
> module MakePrivateArraySig (T : T) = struct
> module type Sig = sig
> type t = private int
> val of_int : int -> t
> val to_int : t -> int
> val length : T.t array -> int
> val get : T.t array -> t -> T.t
> val set : T.t array -> t -> T.t -> unit
> val make : int -> T.t -> T.t array
> val create : int -> T.t -> T.t array
> val init : int -> (t -> T.t) -> T.t array
> val append : T.t array -> T.t array -> T.t array
> val concat : T.t array list -> T.t array
> val to_list : T.t array -> T.t list
> val of_list : T.t list -> T.t array
> val iter : (T.t -> unit) -> T.t array -> unit
> val map : (T.t -> 'b) -> T.t array -> 'b array
> val iteri : (t -> T.t -> unit) -> T.t array -> unit
> val mapi : (t -> T.t -> 'b) -> T.t array -> 'b array
> val fold_left : (T.t -> 'b -> T.t) -> T.t -> 'b array -> T.t
> val fold_right : (T.t -> 'b -> 'b) -> T.t array -> 'b -> 'b
> val unsafe_get : T.t array -> int -> T.t
> val unsafe_set : T.t array -> int -> T.t -> unit
> end
> end
>
> module type IntArrayType = sig
> module T : sig type t = int end
> include MakePrivateArraySig(T).Sig
> end
>
> module type FloatArrayType = sig
> module T : sig type t = float end
> include MakePrivateArraySig(T).Sig
> end
>
> module IntArray : IntArrayType = struct
> type t = int
> module T = struct type t = int end
> include Array
> let of_int x = x
> let to_int x = x
> end
>
> module FloatArray : FloatArrayType = struct
> type t = int
> module T = struct type t = float end
> include Array
> let of_int x = x
> let to_int x = x
> end
>
> -----------------------
> This is clearly the solution for the first question, but I'll be forced to
> write a signature for each array ... I "feel" that there is a clean way of
> doing this ...
>
> -----------------------
>
> module StringArray : Sig = struct
> type t = int
> include Array
> let of_int x = x
> let to_int x = x
> end
> ;;
> module type Sig =
> sig
> type t = private int
> val of_int : int -> t
> val to_int : t -> int
> val length : string array -> int
> val get : string array -> t -> string
> val set : string array -> t -> string -> unit
> val make : int -> string -> string array
> val create : int -> string -> string array
> val init : int -> (t -> string) -> string array
> val append : string array -> string array -> string array
> val concat : string array list -> string array
> val to_list : string array -> string list
> val of_list : string list -> string array
> val iter : (string -> unit) -> string array -> unit
> val map : (string -> 'a) -> string array -> 'a array
> val iteri : (t -> string -> unit) -> string array -> unit
> val mapi : (t -> string -> 'a) -> string array -> 'a array
> val fold_left : (string -> 'a -> string) -> string -> 'a array -> string
> val fold_right : (string -> 'a -> 'a) -> string array -> 'a -> 'a
> val unsafe_get : string array -> int -> string
> val unsafe_set : string array -> int -> string -> unit
> end
>
> # let c = StringArray.make 10 "a";;
> val c : string array = [|"a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"|]
> # StringArray.set c 1 "aa";;
> Error: This expression has type int but an expression was expected of type
> StringArray.t
> # StringArray.set c (StringArray.of_int 1) "aa";;
> - : unit = ()
> # c;;
> - : string array = [|"a"; "aa"; "a"; "a"; "a"; "a"; "a"; "a"; "a"; "a"|]
> #
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa-roc.inria.fr/wws/info/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Caml-list] Arrays and private types
2012-03-14 23:00 ` Gabriel Scherer
@ 2012-03-15 11:04 ` Pietro Abate
2012-03-15 13:18 ` Gabriel Scherer
0 siblings, 1 reply; 4+ messages in thread
From: Pietro Abate @ 2012-03-15 11:04 UTC (permalink / raw)
To: caml-list
On 15/03/12 00:00, Gabriel Scherer wrote:
> Here is a proposal:
> https://gitorious.org/gasche-snippets/private-array-keys-type/blobs/master/private_array_key_types.ml
>
> It works by using a functor to generate "fresh" private types for
> keys. Note that the arrays themselves are still polymorphic (no
> IntArray FloatArray etc.). The user still has to use the discipline to
> produce a new application of ArrayMake each time she wants to use a
> different kind of array: if she only does `module A = ArrayMake(struct
> end)` and then use `A` for everything, there will be no additional
> safety guarantee.
Thanks Gabriel, very nice solution. If I go this way, I guess there is
no way to access array elements using the usual a.(i) syntax (where i
= M.key i)... (I've noticed your cleaver use of private on the array
type to avoid using the normal array syntax on your private arrays).
Is this a problem I can solve using a camlp4 decorator ?
This seems a bit complicated as the a.(i) syntax will be context
dependent, that is, the same syntax used with two different array types
should be translated to different get/set calls... and at the camlp4
level I don't have access to type information... Ideally, instead of
changing all my array access calls, I'd like just to change the type
of my indexes such that all my generic ints will be replaced by
M.key of the appropriate type...
p
ps: please do not Cc me. I'm subscribed to the list.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Caml-list] Arrays and private types
2012-03-15 11:04 ` Pietro Abate
@ 2012-03-15 13:18 ` Gabriel Scherer
0 siblings, 0 replies; 4+ messages in thread
From: Gabriel Scherer @ 2012-03-15 13:18 UTC (permalink / raw)
To: caml-list
> Thanks Gabriel, very nice solution. If I go this way, I guess there is
> no way to access array elements using the usual a.(i) syntax (where i
> = M.key i)... [...]
> Is this a problem I can solve using a camlp4 decorator ?
I don't think you need -- nor want to use -- a camlp4 extension. a.(i)
is desugared into (Array.get a i) at a purely syntactical level in
OCaml, so you could overload its behavior by changing the Array module
in the typing environment.
With my example you could write, for example:
module A1 = ArrayMake(struct end)
let () =
let module Array = A1 in
let k = A1.key in
assert (A1.make 3 true).(k 2);;
You could even define the ArrayMake functor so that it returns a
structure with an Array submodule. You would then write, using 3.12
"local open" syntax:
module A1 = ArrayMake(struct end)
let () =
let open A1 in
assert (Array.make 3 true).(k 2)
That said, I don't think that the slight readability benefit of
writing a.(i) instead of (get a i) will outweigh the confusion among
your readers that don't understand what you're doing with this weird
Array stuff.
On Thu, Mar 15, 2012 at 12:04 PM, Pietro Abate
<Pietro.Abate@pps.jussieu.fr> wrote:
> On 15/03/12 00:00, Gabriel Scherer wrote:
>> Here is a proposal:
>> https://gitorious.org/gasche-snippets/private-array-keys-type/blobs/master/private_array_key_types.ml
>>
>> It works by using a functor to generate "fresh" private types for
>> keys. Note that the arrays themselves are still polymorphic (no
>> IntArray FloatArray etc.). The user still has to use the discipline to
>> produce a new application of ArrayMake each time she wants to use a
>> different kind of array: if she only does `module A = ArrayMake(struct
>> end)` and then use `A` for everything, there will be no additional
>> safety guarantee.
>
> Thanks Gabriel, very nice solution. If I go this way, I guess there is
> no way to access array elements using the usual a.(i) syntax (where i
> = M.key i)... (I've noticed your cleaver use of private on the array
> type to avoid using the normal array syntax on your private arrays).
>
> Is this a problem I can solve using a camlp4 decorator ?
>
> This seems a bit complicated as the a.(i) syntax will be context
> dependent, that is, the same syntax used with two different array types
> should be translated to different get/set calls... and at the camlp4
> level I don't have access to type information... Ideally, instead of
> changing all my array access calls, I'd like just to change the type
> of my indexes such that all my generic ints will be replaced by
> M.key of the appropriate type...
>
> p
>
> ps: please do not Cc me. I'm subscribed to the list.
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa-roc.inria.fr/wws/info/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-03-15 13:19 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-14 20:12 [Caml-list] Arrays and private types Pietro Abate
2012-03-14 23:00 ` Gabriel Scherer
2012-03-15 11:04 ` Pietro Abate
2012-03-15 13:18 ` Gabriel Scherer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox