List Info

Thread: "ocaml_beginners"::[] De-unifying variant types




"ocaml_beginners"::[] De-unifying variant types
country flaguser name
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 ("&quot;, 0, false) in
process_query array_to_movie converter_template result

let process_actors result =
let converter_template = Actor ("&quot;, 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
country flaguser name
United Kingdom
2007-07-25 09:46:53

Take a look at PG'OCaml (http://merjis.com/developers/pgocaml) as it
solves this problem already in a type-safe way.

Rich.

--
Richard Jones
Red Hat

__._,_.___
.

__,_._,___
Re: "ocaml_beginners"::[] De-unifying variant types
country flaguser name
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.
&gt;
>
> val process_movies : string array array -> movie_t array
&gt; 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.&quot;

-- Neko Case

Life is unfair. Kill yourself or get over it.
-- Black Box Recorder

__._,_.___
Recent Activity
Visit Your Group
SPONSORED LINKS
Yahoo! Finance

It's Now Personal

Guides, news,

advice & more.

Search Ads

Get new customers.

List your web site

in Yahoo! Search.

Yoga Groups

Exchange insights

with members of

the yoga community.

Re: "ocaml_beginners"::[] De-unifying variant types
country flaguser name
United Kingdom
2007-07-25 09:30:37

On Wednesday 25 July 2007 13:52:55 cultural_sublimation wrote:
&gt; 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;
&gt; converted

That is "Array.map".

> let process_movies result =
> let converter_template = Movie ("&quot;, 0, false) in
> process_query array_to_movie converter_template result
&gt;
> let process_actors result =
> let converter_template = Actor ("&quot;, 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:
&gt;
>
> val process_movies : string array array -> query_result array
&gt; val process_actors : string array array -> query_result array
&gt;
>
> 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
country flaguser name
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:
&gt; 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
country flaguser name
United Kingdom
2007-07-27 14:56:37

On Fri, Jul 27, 2007 at 08:27:54AM -0700, cultural_sublimation wrote:
&gt; P.S. The dependencies list in the project homepage is missing the CSV
> library.

Now fixed - thanks.

Rich.

--
Richard Jones
Red Hat

__._,_.___
Recent Activity
Visit Your Group
SPONSORED LINKS
Yahoo! Finance

It's Now Personal

Guides, news,

advice & more.

Yoga Resources

on Yahoo! Groups

Take the stress

out of your life.

[1-6]

about | contact  Other archives ( Real Estate discussion Medical topics )