caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Brian Rogoff <bpr@artisan.com>
To: Diego-Olivier.FERNANDEZ-PONS@cicrp.jussieu.fr
Cc: caml-list@inria.fr
Subject: Polymorphic recursion 9Was Re: [Caml-list] Doubly-linked list)
Date: Mon, 19 Aug 2002 08:58:29 -0700	[thread overview]
Message-ID: <15713.5541.413031.271962@granite.artisan.com> (raw)
In-Reply-To: <Pine.A32.3.95.1020819121715.76782C-100000@ibm1.cicrp.jussieu.fr>

Diego Olivier Fernandez Pons writes:
> Brian Rogoff a écrit :
> > With OCaml 3.05 and above, you'll be able to use polymorphic methods to 
> > get non-uniform recursion. This issue has come up a lot on the list 
> > (see the archives) over the years and several proposals were made for 
> > adding this capability to the language. I don't know if adding this 
> > feature is a priority for the developers; it isn't clear that the data
> > structures in Okasaki's book constitute a strong enough argument for 
> > adding it. 
> 
> Non-uniform recursion allows you to capture structure invariants in
> your type, which means that the correction of the algorithms will not
> be proved by the programmer but by the type-checker. 

Oh I'm not arguing that point, I totally agree that it's omission is a 
bad thing. However, not everyone agrees, since you it becomes a lot tougher
to build a monomorphizing compiler if you allow it, though it has been 
suggested that the same tricks you use to manually remove polymorphic
recursion could be used in an SSC (sufficiently smart compiler). 

Anyways, since OCaml 3.05 allows first class polymorphism on records, you
don't even need to use "polymorphic recots" to get non-uniform recursion; 
simply mapping the OOP to records does the trick. Here's the first example
from OKasaki which uses polymorphic recursion, done in OCaml with this 
direct approach 

module type RANDOM_ACCESS_LIST =
  sig
    type 'a ra_list

    val empty   : 'a ra_list
    val is_empty : 'a ra_list -> bool

    val cons    : 'a -> 'a ra_list -> 'a ra_list
    val head    : 'a ra_list -> 'a
    val tail    : 'a ra_list -> 'a ra_list
    val lookup  : int -> 'a ra_list -> 'a
    val update  : int -> 'a -> 'a ra_list -> 'a ra_list
  end

module AltBinaryRandomAccessList : RANDOM_ACCESS_LIST =
  (* assumes polymorphic recursion! *)
  struct 
    type 'a ra_list = Nil
    | Zero of ('a * 'a) ra_list
    | One of 'a * ('a * 'a) ra_list

    let empty = Nil
    let is_empty = function Nil -> true | _ -> false

    (* Use first class polymorphism to get the effect of explicitly typing 
       the polymorphic recursion 
    *)
    type dictionary = 
      { cons : 'a. dictionary -> 'a -> 'a ra_list -> 'a ra_list;
	uncons : 'a. dictionary -> 'a ra_list -> 'a * 'a ra_list;
	lookup : 'a. dictionary -> int -> 'a ra_list -> 'a;
	fupdate : 'a. dictionary -> ('a -> 'a) -> int -> 'a ra_list -> 'a 
ra_list
      }

    (* Define the methods, taking care that the recursive calls go through
       the dictionary
    *)

    let cons' dict x l =
      match l with
	Nil -> One (x, Nil)
      | Zero ps -> One (x, ps)
      | One (y,b) -> Zero (dict.cons dict (x, y) b)

    let uncons' dict l =
      match l with
	Nil -> raise Not_found
      | One (x,Nil) -> (x,Nil)
      | One (x,ps) -> (x, Zero ps)
      | Zero ps -> 
	  let ((x,y),ps') = dict.uncons dict ps in 
	  (x, One (y, ps'))

    let lookup' dict i l = 
      match i,l with 
	(i, Nil) -> raise Not_found
      | (0, One (x, ps)) -> x
      | (i, One (x, ps)) -> dict.lookup dict (pred i) (Zero ps)
      | (i, Zero ps) -> 
	  let (x, y) = dict.lookup dict (i / 2) ps
	  in if i mod 2 = 0 then x else y

    let rec fupdate' dict f i l =
      match i,l with 
	(i, Nil) -> raise Not_found
      | (0, One (x, ps)) -> One (f x, ps)
      | (i, One (x, ps)) -> dict.cons dict x (dict.fupdate dict f (i-1) (Zero 
ps))
      | (i, Zero ps) ->
	  let f' (x, y) = if i mod 2 = 0 then (f x, y) else (x, f y) in 
	  Zero (dict.fupdate dict f' (i / 2) ps)


    (* Make the sole dictionary which will be called *)

    let methods = 
      { cons = cons'; uncons = uncons'; lookup = lookup'; fupdate = fupdate' }

    (* Make the actual functions *)
    let cons x l = cons' methods x l 
    let uncons l = uncons' methods l 
    let head xs = let (x, _) = uncons xs in x
    let tail xs = let (_, xs') = uncons xs in xs'
    let lookup i xs = lookup' methods i xs
    let update i y xs = fupdate' methods (fun x -> y) i xs
  end

> I think it is a big improvment. Chris Okasaki's data structure may not
> be a strong enough argument, but more complicated data structures are
> being studied.

I agree, and I hope that in the future we won't have to use hacks like the 
above to get polymorphic recursion, but that it will be supported more
directly. The style above, besides being indirect, is also a little uglier
still when you're using the tail recursive accumulator passing style
because your recursive functions have funny names and signatures. In any
case, this kind of hack will allow you to translate these structures and
won't require much rework when polymorphic recursion is finally added 
"for real"

-- 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


  reply	other threads:[~2002-08-19 15:58 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-08-13  8:00 [Caml-list] Doubly-linked list Oleg
2002-08-13  8:54 ` Markus Mottl
2002-08-13 15:52   ` Oleg
2002-08-13 11:00 ` Diego Olivier Fernandez Pons
2002-08-13 14:30   ` Oleg
2002-08-13 15:11     ` Anton Moscal
2002-08-13 16:12       ` Oleg
2002-08-13 17:16         ` Max Kirillov
2002-08-14  0:49           ` Max Kirillov
2002-08-13 18:23         ` Anton E. Moscal
2002-08-13 16:16   ` Brian Rogoff
2002-08-14  8:13     ` Diego Olivier Fernandez Pons
2002-08-14 15:43       ` Brian Rogoff
2002-08-19 10:38         ` Diego Olivier Fernandez Pons
2002-08-19 15:58           ` Brian Rogoff [this message]
2002-08-21  8:04             ` Polymorphic recursion 9Was Re: [Caml-list] Doubly-linked list) Diego Olivier Fernandez Pons
2002-08-21 15:48               ` Brian Rogoff
2002-08-23  8:14                 ` Diego Olivier Fernandez Pons
2002-08-23 21:57               ` John Max Skaller
2002-08-27 13:00                 ` Diego Olivier Fernandez Pons
2002-08-28 14:50                   ` John Max Skaller
2002-08-28 17:27                     ` [Caml-list] FELIX (was: Polymorphic recursion) Oleg
2002-08-19 23:17 ` [Caml-list] Doubly-linked list james woodyatt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=15713.5541.413031.271962@granite.artisan.com \
    --to=bpr@artisan.com \
    --cc=Diego-Olivier.FERNANDEZ-PONS@cicrp.jussieu.fr \
    --cc=caml-list@inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).