|
List Info
Thread: "ocaml_beginners"::[] De-unifying variant types
|
|
| "ocaml_beginners"::[]
De-unifying variant types |
  United States |
2007-07-25 07:52:55 |
|
Hi,
Here's the situation: I am building a small module to encapsulate the
nasty type-unsafe task of extracting data stored in a Postgresql database.
(I am using the postgresql-ocaml bindings by Markus Mottl to connect
to Postgresql).
For simplicity sake, let us assume there are only two tables in
the database: "movies" (containing 3 fields: title, year, and B&W,
respectively of types text, integer, and boolean), and "actors"
(containing 2 fields: name and age, of text and integer types).
Now, as far as I can tell, regardless of the Postgresql datatypes, any
row resulting from a SELECT statement will be seen by the Ocaml program
as a "string array". Therefore, I have made two simple functions that
convert the "string array" into proper tuples of movies and actors:
type movie_t = string * int * bool
type actor_t = string * int
type query_result = Movie of movie_t | Actor of actor_t
let array_to_movie a = Movie (a.(0), int_of_string a.(1),
bool_of_string a.(2))
let array_to_actor a = Actor (a.(0), int_of_string a.(2))
The reason why the movie_t and actor_t were unified under that
"query_result" variant is because there is a "process_query" function
which should accept results based both on movies or actors:
let process_query array_converter converter_template result =
let size = Array.length result in
let converted = Array.make size converter_template in
for i = 0 to size-1 do
converted.(i) <- array_converter (result.(i))
done;
converted
Now, all of the these functions are fairly low-level and are not meant
to be used
directly by the users of the module. Instead, the user should handle
all tasks
via two other functions, process_movies and process_actors, as follows:
let process_movies result =
let converter_template = Movie ("", 0, false) in
process_query array_to_movie converter_template result
let process_actors result =
let converter_template = Actor ("", 0) in
process_query array_to_actor converter_template result
This is all fine and dandy, except that because of the unification,
the signature of both process_movies and process_actors is the same:
val process_movies : string array array -> query_result array
val process_actors : string array array -> query_result array
My question is the following: how do I undo the unification of movie_t
and actor_t, so that externally, the signatures of these functions are
different? (listed below). I don't want the caller to be bothering
with matches, and quite frankly, the fact that movie_t and actor_t were
unified is an implementation detail, used only to avoid the duplication
of the process_query code.
val process_movies : string array array -> movie_t array
val process_actors : string array array -> actor_t array
Thanks a lot for your help!!
Cheers,
C.S.
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
De-unifying variant types |
  United Kingdom |
2007-07-25 09:46:53 |
|
__,_._,___
|
| Re: "ocaml_beginners"::[]
De-unifying variant types |
  United States |
2007-07-25 10:12:24 |
|
On Wed, 25 Jul 2007, cultural_sublimation wrote:
> My question is the following: how do I undo the unification of movie_t
> and actor_t, so that externally, the signatures of these functions are
> different? (listed below). I don't want the caller to be bothering
> with matches, and quite frankly, the fact that movie_t and actor_t were
> unified is an implementation detail, used only to avoid the duplication
> of the process_query code.
>
>
> val process_movies : string array array -> movie_t array
> val process_actors : string array array -> actor_t array
Well, unfortunately, if the output of the same function, you're out of
luck, as they have to share the same output type. You'd need to offer up
a set of refinement functions for each of the cases you want to separate
out, e.g.
let refine_movie = function Movie m -> m | _ -> assert false;;
let refine_actor = function Actor a -> a | _ -> assert false;;
and so on.
I know it's not what you want, but unless you do a lot more work to hide
the way the type system works in OCaml, you're stuck with it, as you won't
be able to come up with a useful function of type string array array -> 'a
array, which is what you're asking for.
William D. Neumannn
---
"There's just so many extra children, we could just feed the
children to these tigers. We don't need them, we're not doing
anything with them.
Tigers are noble and sleek; children are loud and messy."
-- Neko Case
Life is unfair. Kill yourself or get over it.
-- Black Box Recorder
__._,_.___
|
| Re: "ocaml_beginners"::[]
De-unifying variant types |
  United Kingdom |
2007-07-25 09:30:37 |
|
On Wednesday 25 July 2007 13:52:55 cultural_sublimation wrote:
> type movie_t = string * int * bool
> type actor_t = string * int
Use records here to be more descriptive:
module Movie = struct
type t = {name: string; foo: int; bar : bool}
let of a = function
| [|name; foo; bar|] ->
{name=name; foo=int_of_string foo; bar=bool_of_string bar}
| _ -> invalid_arg "Movie.of"
end
> type query_result = Movie of movie_t | Actor of actor_t
Remove this type.
> let process_query array_converter converter_template result =
> let size = Array.length result in
> let converted = Array.make size converter_template in
> for i = 0 to size-1 do
> converted.(i) <- array_converter (result.(i))
> done;
> converted
That is "Array.map".
> let process_movies result =
> let converter_template = Movie ("", 0, false) in
> process_query array_to_movie converter_template result
>
> let process_actors result =
> let converter_template = Actor ("", 0) in
> process_query array_to_actor converter_template result
The conversion is now trivial:
Array.map Movie.of
so I would not bother factoring it out. Instead, have a query_movie function:
let query_movie db query = Array.map Movie.of (Sql.query db query)
let query_actor db query = Array.map Actor.of (Sql.query db query)
> This is all fine and dandy, except that because of the unification,
> the signature of both process_movies and process_actors is the same:
>
>
> val process_movies : string array array -> query_result array
> val process_actors : string array array -> query_result array
>
>
> My question is the following: how do I undo the unification of movie_t
> and actor_t, so that externally, the signatures of these functions are
> different? (listed below).
You must make them separate types (like my records).
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?e
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
De-unifying variant types |
  United States |
2007-07-27 10:27:54 |
|
> The version on the site was a bit old. I wrote some documentation a
> while back which is now in 0.8, here:
> http://merjis.com/developers/pgocaml
Hi,
Excellent! Now that I've played a bit more with PG'OCaml, I am liking it
more and more.
I think that with more extensive documentation and a GODI package this could
very well
become the de facto Ocaml standard for connecting to Postgresql.
I'll keep you posted of suggestions/impressions once I start using it in
"the real world".
Cheers,
C.S.
P.S. The dependencies list in the project homepage is missing the CSV
library.
--
View this message in context: http://www.nabble.com/%22ocaml_beginners%22%3A%3A---De-unifying-variant-types-tf4142036.html#a11831501
Sent from the Ocaml Beginner mailing list archive at Nabble.com.
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
De-unifying variant types |
  United Kingdom |
2007-07-27 14:56:37 |
|
On Fri, Jul 27, 2007 at 08:27:54AM -0700, cultural_sublimation wrote:
> P.S. The dependencies list in the project homepage is missing the CSV
> library.
Now fixed - thanks.
Rich.
--
Richard Jones
Red Hat
__._,_.___
|
[1-6]
|
|