Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] A G'Caml question
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Brian Rogoff <bpr@b...>
Subject: [Caml-list] A G'Caml question
Hi,
    One of the important issues with overloading is whether one has 
to define a "generic" function all in one place or if you can build it up 
piecemeal from already existing generic functions. I played a bit, learned 
some things, and now I have some questions. 

I start with the obvious "plus" function, and extend it so that in 
concatenates strings. 

# generic plus = case
    int -> int -> int => (+)
  | float -> float -> float => (+.) ;;  
val plus : $a -> $a -> $a [ int -> int -> int 
                          | float -> float -> float  ] =
  <fun>
# plus 1 2;;
- : int = 3
# plus 1.0 2.0;;
- : float = 3
# plus "1" "2";;
This generic full instance is used with type string -> string -> string
 which is not its valid instance of 
$a -> $a -> $a [ int -> int -> int 
               | float -> float -> float  ]
# generic plus = case 
  string -> string -> string => (^) 
  | $a -> $a -> $a => plus ;;  
val plus : $a -> $a -> $a
  [ string -> string -> string 
  | $a -> $a -> $a && plus : $a -> $a -> $a  ] = <fun>
# plus 1 1;;
- : int = 2
# plus "1" "2.0";;
- : string = "12.0"

Cool, for some very simple cases, it we can incrementally build up a 
generic function from pieces. I think it's obvious that we'll get into 
trouble with recursive generics. 

# generic rec print = case 
  | int -> unit => print_int
  | string -> unit => print_string
  | $a list -> unit => 
      function [] -> ()
      |   x :: xs -> print x; print xs
  ;;            
  val print : $a -> unit
  [ int -> unit 
  | string -> unit 
  | $a list -> unit && print : $a -> unit && print : $a list -> unit  ] =
  <fun>
# print 23;;
23- : unit = ()
# print 23.0;;
This generic full instance is used with type float -> unit
 which is not its valid instance of 
$a -> unit
[ int -> unit 
| string -> unit 
| $a list -> unit && print : $a -> unit && print : $a list -> unit  ]

OK, lets try the same thing as before, 

# generic rec print = case float -> unit => print_float | $a -> unit =>
print;;
val print : $a -> unit
  [ float -> unit 
  | $a -> unit && print : $a -> unit  ] = <fun>

# print 1.0;;
1- : unit = ()
# print 1 (* infinite loop! *)

Well, that should be expected, since we try and print an int, which isn't
a float, so we try (from $a -> unit => print) to print, ad infinitum. Is
there a way out? If we try and rename print and call that, it still won't work, 
since we want a form of "open recursion" here: if I add a case for float I 
want to be able to print float lists. With the original print
reinstalled...

# let print' = print ;;
val print' : $a -> unit [ $a -> unit && print : $a -> unit  ] = <fun>
# generic rec print = case float -> unit => print_float | $a -> unit =>
print';;
val print : $a -> unit
  [ float -> unit 
  | $a -> unit && print' : $a -> unit  ] = <fun>
# print 1.0;;
1- : unit = ()
# print [1;2;3];;
123- : unit = ()
# print [1.0;2.0;3.0];; 
This generic full instance is used with type float list -> unit
 which is not its valid instance of 
$a -> unit [ float -> unit 
           | $a -> unit && print' : $a -> unit  ]

Is there some trick to build up recursive generics by parts? One thing 
to do is to break the recursive generic into a non-recursive generic
and a recursive function which applies the generic to the elements, 
but that feels like cheating. Maybe open recursion for generics would 
be desirable, so that I can add a new case and have the recursive call in 
an existing case call the new one? Yes, it's a half baked idea, but maybe 
a better cook can finish baking...

-- Brian



-------------------
Bug reports: http://caml.inria.fr/bin/caml-bugs  FAQ: http://caml.inria.fr/FAQ/
To unsubscribe, mail caml-list-request@inria.fr  Archives: http://caml.inria.fr