caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Fwd: Polymorphic optional label argument, with default
@ 2004-04-10 21:36 Richard Jones
  2004-04-10 22:40 ` Gerd Stolpmann
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Richard Jones @ 2004-04-10 21:36 UTC (permalink / raw)
  To: caml-list

Hi:

I posted the message below originally on ocaml_beginners.  There were
many helpful responses, and the general consensus was that this was
not possible, but no one could give a definitive answer.  I just
wanted to confirm on the 'grown-ups' list (:-) if this is really true
before I finalise the API I am designing.

Thanks,

Rich.

To: ocaml_beginners@yahoogroups.com
From: Richard Jones <rich@annexia.org>
Subject: Polymorphic optional label argument, with default

I have a function defined:

  let plot ?(labels = string_of_int) graph =
    (* ... *)

The idea of the optional 'labels' argument is to specify a polymorphic
function 'a -> string which is used to print labels stored in the
'graph' argument.

The problem is that because string_of_int is obviously int -> string,
my function is typed as:

  plot : ?labels : (int -> string) -> (* ... int ... *) -> unit

but I want it to be typed as:

  plot : ?labels : ('a -> string) -> (* ... 'a ... *) -> unit

[The 'a types are the same type.  If I leave out the initializer, then
it works.]

How to?

Rich.
-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
Perl4Caml lets you use any Perl library in your type-safe Objective
CAML programs. http://www.merjis.com/developers/perl4caml/

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-10 21:36 [Caml-list] Fwd: Polymorphic optional label argument, with default Richard Jones
@ 2004-04-10 22:40 ` Gerd Stolpmann
  2004-04-11  0:03   ` skaller
  2004-04-10 23:52 ` Matt Gushee
  2004-04-11  6:26 ` Brian Hurt
  2 siblings, 1 reply; 10+ messages in thread
From: Gerd Stolpmann @ 2004-04-10 22:40 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

On Sam, 2004-04-10 at 23:36, Richard Jones wrote:
> Hi:
> 
> I posted the message below originally on ocaml_beginners.  There were
> many helpful responses, and the general consensus was that this was
> not possible, but no one could give a definitive answer.  I just
> wanted to confirm on the 'grown-ups' list (:-) if this is really true
> before I finalise the API I am designing.
> 
> Thanks,
> 
> Rich.
> 
> To: ocaml_beginners@yahoogroups.com
> From: Richard Jones <rich@annexia.org>
> Subject: Polymorphic optional label argument, with default
> 
> I have a function defined:
> 
>   let plot ?(labels = string_of_int) graph =
>     (* ... *)
> 
> The idea of the optional 'labels' argument is to specify a polymorphic
> function 'a -> string which is used to print labels stored in the
> 'graph' argument.
> 
> The problem is that because string_of_int is obviously int -> string,
> my function is typed as:
> 
>   plot : ?labels : (int -> string) -> (* ... int ... *) -> unit
> 
> but I want it to be typed as:
> 
>   plot : ?labels : ('a -> string) -> (* ... 'a ... *) -> unit
> 
> [The 'a types are the same type.  If I leave out the initializer, then
> it works.]
> 
> How to?

This does not work. If "plot" were not specialised to int labels, you
could call

plot string_graph

(i.e. without ~labels), and where string_graph would be another
specialisation to string labels. This is unsound, because you would
apply string_of_int to strings.

One way out is the two function solution already discussed in
ocaml-beginners (i.e. having "plot" for the polymorphic case, and
"plot_int" for the int case).

Another idea is to store the default for "labels" in the graph. (Or to
implement the graphs with classes, which is a similar approach, but more
effective when you have several such defaults.)

I suppose there is also a good solution with extensional polymorphism,
but this isn't yet in mainstream O'Caml.

Gerd
-- 
------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany 
gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
------------------------------------------------------------

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-10 21:36 [Caml-list] Fwd: Polymorphic optional label argument, with default Richard Jones
  2004-04-10 22:40 ` Gerd Stolpmann
@ 2004-04-10 23:52 ` Matt Gushee
  2004-04-11  6:26 ` Brian Hurt
  2 siblings, 0 replies; 10+ messages in thread
From: Matt Gushee @ 2004-04-10 23:52 UTC (permalink / raw)
  To: caml-list

On Sat, Apr 10, 2004 at 10:36:16PM +0100, Richard Jones wrote:
> 
> I have a function defined:
> 
>   let plot ?(labels = string_of_int) graph =
>     (* ... *)

I don't think I can directly address your problem as stated here, but I
have one or two observations that might be relevant:

 * I had to grapple with a similar issue in developing my ChartPak
   toolkit: how do you generate a string from an arbitrary data type?
   I decided on an architecture where each chart type is implemented as
   an OCaml module. That module transforms a data set into a collection
   of abstract graphical objects (by that I mean that their shapes and
   relative positions are defined, but their actual dimensions are not).
   This collection is passed to a renderer which creates the actual
   image.

   This approach is more complex internally and less dynamic than I
   would like, but it does make for an API that is both fairly simple
   to use and not too hard to extend (assuming you can compile OCaml 
   code).

 * Do you really need to handle arbitrary data types? You will certainly
   have floats, ints, and strings, but what else? Maybe you should focus
   on providing a simple interface for the most common data types.

 * BTW, what sort of application/library are you working on here? If it
   is much like mine (and is open source and intended for general
   distribution), maybe we should think about joining forces.


-- 
Matt Gushee                 When a nation follows the Way,
Englewood, Colorado, USA    Horses bear manure through
mgushee@havenrock.com           its fields;
http://www.havenrock.com/   When a nation ignores the Way,
                            Horses bear soldiers through
                                its streets.
                                
                            --Lao Tzu (Peter Merel, trans.)

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-10 22:40 ` Gerd Stolpmann
@ 2004-04-11  0:03   ` skaller
  0 siblings, 0 replies; 10+ messages in thread
From: skaller @ 2004-04-11  0:03 UTC (permalink / raw)
  To: Gerd Stolpmann; +Cc: Richard Jones, caml-list

On Sun, 2004-04-11 at 08:40, Gerd Stolpmann wrote:
> On Sam, 2004-04-10 at 23:36, Richard Jones wrote:

> > I have a function defined:
> > 
> >   let plot ?(labels = string_of_int) graph =
> >     (* ... *)
> > 
> > The idea of the optional 'labels' argument is to specify a polymorphic
> > function 'a -> string which is used to print labels stored in the
> > 'graph' argument.
> > 

> This does not work. If "plot" were not specialised to int labels, you
> could call
> 
> plot string_graph

Now hang on! Let's suppose we have a type

'a graph

and we want:

	plot g 

to work if g is type 'int graph'. On the other hand
if g is type float graph, it fails and we can write

	plot ~labels:string_of_float g

We could also write

	plot ~labels:polyprint g

for any graph type, where polyprint:'a -> string would likely print
the label's physical address -- since that's about all
a polymorphic print could do .. unless it's an int.
That can be determined at run time.

It seems to me there's nothing unsound here,
but that doesn't mean we can do it ..

I'd actually make the default polyprint.
That way you can print any graph, and if you 
desire you can add a print routine specialised
to the label type.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-10 21:36 [Caml-list] Fwd: Polymorphic optional label argument, with default Richard Jones
  2004-04-10 22:40 ` Gerd Stolpmann
  2004-04-10 23:52 ` Matt Gushee
@ 2004-04-11  6:26 ` Brian Hurt
  2004-04-11  8:33   ` Richard Jones
  2 siblings, 1 reply; 10+ messages in thread
From: Brian Hurt @ 2004-04-11  6:26 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

On Sat, 10 Apr 2004, Richard Jones wrote:

> Hi:
> 
> I posted the message below originally on ocaml_beginners.  There were
> many helpful responses, and the general consensus was that this was
> not possible, but no one could give a definitive answer.  I just
> wanted to confirm on the 'grown-ups' list (:-) if this is really true
> before I finalise the API I am designing.

Hmm.  Somehow I've gotten unsubscribed from that list.  I should subscribe 
again.

> 
> Thanks,
> 
> Rich.
> 
> To: ocaml_beginners@yahoogroups.com
> From: Richard Jones <rich@annexia.org>
> Subject: Polymorphic optional label argument, with default
> 
> I have a function defined:
> 
>   let plot ?(labels = string_of_int) graph =
>     (* ... *)
> 
> The idea of the optional 'labels' argument is to specify a polymorphic
> function 'a -> string which is used to print labels stored in the
> 'graph' argument.
> 
> The problem is that because string_of_int is obviously int -> string,
> my function is typed as:
> 
>   plot : ?labels : (int -> string) -> (* ... int ... *) -> unit
> 
> but I want it to be typed as:
> 
>   plot : ?labels : ('a -> string) -> (* ... 'a ... *) -> unit
> 
> [The 'a types are the same type.  If I leave out the initializer, then
> it works.]
> 
> How to?
> 

I don't think it's possible.  Consider the following situation: I pass in 
a graph of floats for example, and then forget to specify a labels 
argument.  Now you're passing a float to string_of_int.

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-11  6:26 ` Brian Hurt
@ 2004-04-11  8:33   ` Richard Jones
  2004-04-11  9:01     ` skaller
  2004-04-11 13:16     ` Jacques Garrigue
  0 siblings, 2 replies; 10+ messages in thread
From: Richard Jones @ 2004-04-11  8:33 UTC (permalink / raw)
  Cc: caml-list

On Sun, Apr 11, 2004 at 01:26:24AM -0500, Brian Hurt wrote:
> >   plot : ?labels : ('a -> string) -> (* ... 'a ... *) -> unit
> > 
> > [The 'a types are the same type.  If I leave out the initializer, then
> > it works.]
> > 
> > How to?
> > 
> 
> I don't think it's possible.  Consider the following situation: I pass in 
> a graph of floats for example, and then forget to specify a labels 
> argument.  Now you're passing a float to string_of_int.

I'd want this to generate a compile-time error, because the 'a 's
aren't the same.

It's perfectly possible to define this function if one leaves out the
default argument, or sets the default argument to a function typed as
'a -> string.

# let plot ~labels graph = print_endline (labels graph);;
val plot : labels:('a -> string) -> 'a -> unit = <fun>

or:

# let string_of_any x = "foo";;
val string_of_any : 'a -> string = <fun>
# let plot ?(labels = string_of_any) graph = print_endline (labels graph);;
val plot : ?labels:('a -> string) -> 'a -> unit = <fun>

But not if I want the default to be the most common case (which is
that my graph will be a graph of ints).  I want the common case in
there so that most of the time end users of the API won't need to
worry about ~labels and optional arguments.

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
'There is a joke about American engineers and French engineers. The
American team brings a prototype to the French team. The French team's
response is: "Well, it works fine in practice; but how will it hold up
in theory?"'

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-11  8:33   ` Richard Jones
@ 2004-04-11  9:01     ` skaller
  2004-04-11 13:16     ` Jacques Garrigue
  1 sibling, 0 replies; 10+ messages in thread
From: skaller @ 2004-04-11  9:01 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

On Sun, 2004-04-11 at 18:33, Richard Jones wrote:

> But not if I want the default to be the most common case (which is
> that my graph will be a graph of ints).  I want the common case in
> there so that most of the time end users of the API won't need to
> worry about ~labels and optional arguments.

Of course it is trivial to do with two functions:

let plot_extended label_printer g = ...
let plot g = plot_extended string_of_int g

although I still prefer

let plot g = plot_extended polyprint g

since it remains polymorphic.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-11  8:33   ` Richard Jones
  2004-04-11  9:01     ` skaller
@ 2004-04-11 13:16     ` Jacques Garrigue
  2004-04-11 15:23       ` nadji
  1 sibling, 1 reply; 10+ messages in thread
From: Jacques Garrigue @ 2004-04-11 13:16 UTC (permalink / raw)
  To: rich; +Cc: caml-list

From: Richard Jones <rich@annexia.org>
> On Sun, Apr 11, 2004 at 01:26:24AM -0500, Brian Hurt wrote:
> > >   plot : ?labels : ('a -> string) -> (* ... 'a ... *) -> unit
> > > 
> > > [The 'a types are the same type.  If I leave out the initializer, then
> > > it works.]
> > 
> > I don't think it's possible.  Consider the following situation: I pass in 
> > a graph of floats for example, and then forget to specify a labels 
> > argument.  Now you're passing a float to string_of_int.
> 
> I'd want this to generate a compile-time error, because the 'a 's
> aren't the same.
> 
> It's perfectly possible to define this function if one leaves out the
> default argument, or sets the default argument to a function typed as
> 'a -> string.
> 
> # let plot ~labels graph = print_endline (labels graph);;
> val plot : labels:('a -> string) -> 'a -> unit = <fun>
> 
> or:
> 
> # let string_of_any x = "foo";;
> val string_of_any : 'a -> string = <fun>
> # let plot ?(labels = string_of_any) graph = print_endline (labels graph);;
> val plot : ?labels:('a -> string) -> 'a -> unit = <fun>
> 
> But not if I want the default to be the most common case (which is
> that my graph will be a graph of ints).  I want the common case in
> there so that most of the time end users of the API won't need to
> worry about ~labels and optional arguments.

What you are asking for has already been discussed on this list, a few
years ago. Here is my answer at that time:
  http://caml.inria.fr/archives/200102/msg00212.html

Basically, what you are asking for is a new type of constraint, which
is only to be applied when the optional argument is omitted (and as
result the default is selected).
This is not possible in the current type system, and while there are
some uses for that, it would be hard to justify making types more
complex in the general case, just to handle this specific problem.

Note that there is an encoding, which does not provide optional
arguments, but just a way to handle this kind of default in an
explicit way.

module Opt : sig
  type ('a,'b) t
  val omit : ('a,'a) t
  val arg : 'a -> ('a,'b) t
  val get : default:'b -> ('a,'b) t -> 'a
end = struct
  type ('a,'b) opt = Omit | Arg of 'a
  let omit = Omit
  let arg x = Arg x
  let get ~default = function
      Omit -> Obj.magic default
    | Arg x -> x
end

Note that the typing makes this use of Obj.magic OK.

Then your function may be defined to take as argument either Opt.omit
or (Opt.arg f).

This probably doesn't solve your problem, but this may help you to see
the issues involved.

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-11 13:16     ` Jacques Garrigue
@ 2004-04-11 15:23       ` nadji
  2004-04-12  2:25         ` Jacques Garrigue
  0 siblings, 1 reply; 10+ messages in thread
From: nadji @ 2004-04-11 15:23 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: rich, caml-list

Le Sunday 11 April 2004 15:16, Jacques Garrigue a écrit :
> Basically, what you are asking for is a new type of constraint, which
> is only to be applied when the optional argument is omitted (and as
> result the default is selected).
> This is not possible in the current type system, and while there are
> some uses for that, it would be hard to justify making types more
> complex in the general case, just to handle this specific problem.
I would like to point out that a machinery to handle this problem
is guarded recursive datatypes proposed by Xi. It is a framework
that solves a bunch of other problems and is compatible with ml type
system (there is currently at Inria a student working on an Ocaml integration 
of this type system).
Combining it with your labeled parameters leads to a well typed code
analogous to your phantom-type based solution. Some even view
Xi's GRDT as a way to avoid your Obj.magic when matching against 
a phantom type. 
For those interested, the pseudo code would be something like :

guarded 'a opt = Omit with 'a = int | Arg of 'a->unit
let plot : ?(labels:'a opt) -> 'a graph -> unit =
  fun ?(labels=Omit) g ->
  let printing_labels : 'a -> unit = 
     match labels with 
       Omit -> print_int
    | Arg x -> x
  in
  ... printing_labels node_label ...

Nadji

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Caml-list] Fwd: Polymorphic optional label argument, with default
  2004-04-11 15:23       ` nadji
@ 2004-04-12  2:25         ` Jacques Garrigue
  0 siblings, 0 replies; 10+ messages in thread
From: Jacques Garrigue @ 2004-04-12  2:25 UTC (permalink / raw)
  To: nadji; +Cc: caml-list

From: nadji <nadji@noos.fr>
> Le Sunday 11 April 2004 15:16, Jacques Garrigue a ecrit :

> > Basically, what you are asking for is a new type of constraint, which
> > is only to be applied when the optional argument is omitted (and as
> > result the default is selected).
> > This is not possible in the current type system, and while there are
> > some uses for that, it would be hard to justify making types more
> > complex in the general case, just to handle this specific problem.

> I would like to point out that a machinery to handle this problem
> is guarded recursive datatypes proposed by Xi. It is a framework
> that solves a bunch of other problems and is compatible with ml type
> system (there is currently at Inria a student working on an Ocaml integration 
> of this type system).
> Combining it with your labeled parameters leads to a well typed code
> analogous to your phantom-type based solution. Some even view
> Xi's GRDT as a way to avoid your Obj.magic when matching against 
> a phantom type. 
> For those interested, the pseudo code would be something like :
> 
> guarded 'a opt = Omit with 'a = int | Arg of 'a->unit
> let plot : ?(labels:'a opt) -> 'a graph -> unit =
>   fun ?(labels=Omit) g ->
>   let printing_labels : 'a -> unit = 
>      match labels with 
>        Omit -> print_int
>     | Arg x -> x
>   in
>   ... printing_labels node_label ...

I was not aware that there was already work to include guarded types
in ocaml. They are indeed a nice solution to this problem,
particularly as they allow to cleanly separate issues.

Another (less clean) way to do that is with dependant
polymorphic variants, as implemented in a branch of the ocaml CVS:
# let incr ~f x =
    let x = x+1 in
    multimatch f with `None -> x | `Some f -> f x
  ;;
val incr :
  f:[< `None & 'a = int | `Some of int -> 'b & 'a = 'b ] -> int -> 'a = <fun>
# incr ~f:`None 3;;
- : int = 4
# incr ~f:(`Some string_of_int) 3;;
- : string = "4"

(Note that for this to really work, optional arguments would have to
use polymorphic variants, which is why it is not as clean as guarded
types.)

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2004-04-12  2:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-10 21:36 [Caml-list] Fwd: Polymorphic optional label argument, with default Richard Jones
2004-04-10 22:40 ` Gerd Stolpmann
2004-04-11  0:03   ` skaller
2004-04-10 23:52 ` Matt Gushee
2004-04-11  6:26 ` Brian Hurt
2004-04-11  8:33   ` Richard Jones
2004-04-11  9:01     ` skaller
2004-04-11 13:16     ` Jacques Garrigue
2004-04-11 15:23       ` nadji
2004-04-12  2:25         ` 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).