From: james woodyatt <jhw@wetware.com>
To: brogoff <brogoff@speakeasy.net>, Ocaml Trade <caml-list@inria.fr>
Subject: [Caml-list] kaplan-okasaki-tarjan deque (was "looping recursion")
Date: Fri, 30 Jul 2004 11:25:56 -0700 [thread overview]
Message-ID: <E6358338-E255-11D8-995D-000A958FF2FE@wetware.com> (raw)
In-Reply-To: <Pine.LNX.4.58.0407300948350.31375@shell2.speakeasy.net>
[-- Attachment #1: Type: text/plain, Size: 274 bytes --]
On 30 Jul 2004, at 10:07, brogoff wrote:
>
> I would like to see an implementation of the catenable deques only
> using simple list ops (not laziness) described by Kaplan and Tarjan,
> in OCaml.
Sure. Here is the basic implementation I did for performance
comparisons.
[-- Attachment #2: cf_kotdeque.ml --]
[-- Type: application/octet-stream, Size: 18773 bytes --]
(*---------------------------------------------------------------------------*
IMPLEMENTATION cf_kotdeque.ml
Copyright (c) 2003, James H. Woodyatt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*---------------------------------------------------------------------------*)
type 'a buffer =
| B1 of 'a
| B2 of 'a * 'a
| B3 of 'a * 'a * 'a
| B4 of 'a * 'a * 'a * 'a
| B5 of 'a * 'a * 'a * 'a * 'a
| B6 of 'a * 'a * 'a * 'a * 'a * 'a
| B7 of 'a * 'a * 'a * 'a * 'a * 'a * 'a
| B8 of 'a * 'a * 'a * 'a * 'a * 'a * 'a * 'a
let pushBufferL x = function
| B1 a -> B2 (x,a)
| B2 (a,b) -> B3 (x,a,b)
| B3 (a,b,c) -> B4 (x,a,b,c)
| B4 (a,b,c,d) -> B5 (x,a,b,c,d)
| B5 (a,b,c,d,e) -> B6 (x,a,b,c,d,e)
| B6 (a,b,c,d,e,f) -> B7 (x,a,b,c,d,e,f)
| B7 (a,b,c,d,e,f,g) -> B8 (x,a,b,c,d,e,f,g)
| B8 _ as y -> assert (not true); y
let pushBufferR x = function
| B1 a -> B2 (a,x)
| B2 (a,b) -> B3 (a,b,x)
| B3 (a,b,c) -> B4 (a,b,c,x)
| B4 (a,b,c,d) -> B5 (a,b,c,d,x)
| B5 (a,b,c,d,e) -> B6 (a,b,c,d,e,x)
| B6 (a,b,c,d,e,f) -> B7 (a,b,c,d,e,f,x)
| B7 (a,b,c,d,e,f,g) -> B8 (a,b,c,d,e,f,g,x)
| B8 _ as y -> assert (not true); y
let popBufferL = function
| B1 _ -> assert false
| B2 (x,a) -> x, B1 a
| B3 (x,a,b) -> x, B2 (a,b)
| B4 (x,a,b,c) -> x, B3 (a,b,c)
| B5 (x,a,b,c,d) -> x, B4 (a,b,c,d)
| B6 (x,a,b,c,d,e) -> x, B5 (a,b,c,d,e)
| B7 (x,a,b,c,d,e,f) -> x, B6 (a,b,c,d,e,f)
| B8 (x,a,b,c,d,e,f,g) -> x, B7 (a,b,c,d,e,f,g)
let popBufferR = function
| B1 _ -> assert false
| B2 (a,x) -> x, B1 a
| B3 (a,b,x) -> x, B2 (a,b)
| B4 (a,b,c,x) -> x, B3 (a,b,c)
| B5 (a,b,c,d,x) -> x, B4 (a,b,c,d)
| B6 (a,b,c,d,e,x) -> x, B5 (a,b,c,d,e)
| B7 (a,b,c,d,e,f,x) -> x, B6 (a,b,c,d,e,f)
| B8 (a,b,c,d,e,f,g,x) -> x, B7 (a,b,c,d,e,f,g)
type 'a t =
| Z
| Y of 'a buffer
| U of 'a buffer * 'a triple t * ('a * 'a) * 'a triple t * 'a buffer
and 'a triple =
| T1 of 'a buffer
| T2 of 'a buffer * 'a buffer
| T3 of 'a buffer * 'a triple t * 'a buffer
let popLeftNaive = function
| Z ->
assert false
| Y (B1 x) ->
x, Z
| Y b ->
let x, b = popBufferL b in x, Y b
| U (pr, ld, mid, rd, sf) ->
let x, pr = popBufferL pr in x, U (pr, ld, mid, rd, sf)
let popRightNaive = function
| Z ->
assert false
| Y (B1 x) ->
x, Z
| Y b ->
let x, b = popBufferR b in x, Y b
| U (pr, ld, mid, rd, sf) ->
let x, sf = popBufferR sf in x, U (pr, ld, mid, rd, sf)
let rec pushLeft x = function
| Z ->
Y (B1 x)
| Y (B8 (a,b,c,d,e,f,g,h)) ->
U (B4 (x,a,b,c), Z, (d,e), Z, B3 (f,g,h))
| Y b ->
Y (pushBufferL x b)
| U (pr, ld, mid, rd, sf) as d ->
match pr with
| B6 _ ->
let pr, ld, mid, rd, sf = greenLeft pr ld mid rd sf in
U (pushBufferL x pr, ld, mid, rd, sf)
| _ ->
U (pushBufferL x pr, ld, mid, rd, sf)
and pushRight x = function
| Z ->
Y (B1 x)
| Y (B8 (a,b,c,d,e,f,g,h)) ->
U (B3 (a,b,c), Z, (d,e), Z, B4 (f,g,h,x))
| Y b ->
Y (pushBufferR x b)
| U (pr, ld, mid, rd, sf) as d ->
match sf with
| B6 _ ->
let pr, ld, mid, rd, sf = greenRight pr ld mid rd sf in
U (pr, ld, mid, rd, pushBufferR x sf)
| _ ->
U (pr, ld, mid, rd, pushBufferR x sf)
and greenLeft pr ld mid rd sf =
match pr with
| B6 (e1,e2,e3,e4,e5,e6) ->
let ld = (Obj.magic pushLeft) (T1 (B2 (e5,e6))) ld in
B4 (e1,e2,e3,e4), ld, mid, rd, sf
| B3 _ ->
begin
match ld, rd with
| Y _, _
| U _, _ ->
let t, l =
let t, _ = popLeftNaive ld in
match t with
| T1 (B3 _)
| T2 (B3 _, _)
| T3 _ ->
popLeftNaive ld
| _ ->
match (Obj.magic popLeft) ld with
| Some (x,y) -> x, y
| None -> assert false
in
let (T1 x | T2 (x,_) | T3 (x,_,_)) = t in begin
match x with
| B3 (e1,e2,e3) ->
let p = pushBufferR e1 pr in
let x' = B2 (e2,e3) in
let l0 =
match t with
| T3 (_, d', y) -> T3 (x', d', y)
| T2 (_, y) -> T2 (x', y)
| T1 _ -> T1 x'
in
let ld = (Obj.magic pushLeft) l0 l in
p, ld, mid, rd, sf
| B2 (e1,e2) ->
let p = pushBufferR e2 (pushBufferR e1 pr) in
let l' =
match t with
| T3 (_, d', y) ->
let l = (Obj.magic pushLeft) (T1 y) l in
(Obj.magic catenate) d' l
| T1 _ ->
l
| _ ->
assert false
in
p, l', mid, rd, sf
| _ ->
assert false
end
| Z, Y _
| Z, U _ ->
let t, r =
let t, _ = popLeftNaive rd in
match t with
| T1 (B3 _)
| T2 (B3 _, _)
| T3 _ ->
popLeftNaive rd
| _ ->
match (Obj.magic popLeft) rd with
| Some (x,y) -> x, y
| None -> assert false
in
let m1, m2 = mid in
let (T1 x | T2 (x,_) | T3 (x,_,_)) = t in begin
match x with
| B3 (e1,e2,e3) ->
let p = pushBufferR m1 pr in
let mid = m2, e1 in
let x' = B2 (e2,e3) in
let r0 =
match t with
| T3 (_, d', y) -> T3 (x', d', y)
| T2 (_, y) -> T2 (x', y)
| T1 _ -> T1 x'
in
let rd = (Obj.magic pushLeft) r0 r in
p, ld, mid, rd, sf
| B2 (e1,e2) ->
let p = pushBufferR m2 (pushBufferR m1 pr) in
let mid = e1, e2 in
let r' =
match t with
| T3 (_, d', y) ->
let r = (Obj.magic pushLeft) (T1 y) r in
(Obj.magic catenate) d' r
| T1 _ ->
r
| _ ->
assert false
in
p, Z, mid, r', sf
| _ ->
assert false
end
| _ ->
assert false
end
| _ ->
assert false
and greenRight pr ld mid rd sf =
match sf with
| B6 (e6,e5,e4,e3,e2,e1) ->
let rd = (Obj.magic pushRight) (T1 (B2 (e6,e5))) rd in
pr, ld, mid, rd, B4 (e4,e3,e2,e1)
| B3 _ ->
begin
match ld, rd with
| _, Y _
| _, U _ ->
let t, r =
let t, _ = popRightNaive rd in
match t with
| T1 (B3 _)
| T2 (_, B3 _)
| T3 _ ->
popRightNaive rd
| _ ->
match (Obj.magic popRight) rd with
| Some (x,y) -> x, y
| None -> assert false
in
let (T1 x | T2 (_,x) | T3 (_,_,x)) = t in begin
match x with
| B3 (e3,e2,e1) ->
let p = pushBufferL e1 sf in
let x' = B2 (e3,e2) in
let r0 =
match t with
| T3 (y, d', _) -> T3 (y, d', x')
| T2 (y, _) -> T2 (y, x')
| T1 _ -> T1 x'
in
let rd = (Obj.magic pushRight) r0 r in
pr, ld, mid, rd, p
| B2 (e2,e1) ->
let p = pushBufferL e2 (pushBufferL e1 sf) in
let r' =
match t with
| T3 (y, d', _) ->
let r = (Obj.magic pushRight) (T1 y) r in
(Obj.magic catenate) r d'
| T1 _ ->
r
| _ ->
assert false
in
pr, ld, mid, r', p
| _ ->
assert false
end
| Y _, Z
| U _, Z ->
let t, l =
let t, _ = popRightNaive ld in
match t with
| T1 (B3 _)
| T2 (_, B3 _)
| T3 _ ->
popRightNaive ld
| _ ->
match (Obj.magic popRight) ld with
| Some (x,y) -> x, y
| None -> assert false
in
let m2, m1 = mid in
let (T1 x | T2 (_,x) | T3 (_,_,x)) = t in begin
match x with
| B3 (e3,e2,e1) ->
let p = pushBufferL m1 sf in
let mid = e1, m2 in
let x' = B2 (e3,e2) in
let l0 =
match t with
| T3 (y, d', _) -> T3 (y, d', x')
| T2 (y, _) -> T2 (y, x')
| T1 _ -> T1 x'
in
let ld = (Obj.magic pushRight) l0 l in
pr, ld, mid, rd, p
| B2 (e2,e1) ->
let p = pushBufferL m2 (pushBufferL m1 sf) in
let mid = e2, e1 in
let l' =
match t with
| T3 (y, d', _) ->
let l = (Obj.magic pushRight) (T1 y) l in
(Obj.magic catenate) l d'
| T1 _ ->
l
| _ ->
assert false
in
pr, l', mid, Z, p
| _ ->
assert false
end
| _ ->
assert false
end
| _ ->
assert false
and popLeft = function
| Z ->
None
| Y (B1 x) ->
Some (x, Z)
| Y b ->
let x, b = popBufferL b in
Some (x, Y b)
| U ((B4 _ | B5 _ | B6 _ as pr), ld, mid, rd, sf) ->
let x, pr = popBufferL pr in
Some (x, U (pr, ld, mid, rd, sf))
| U ((B3 (x,e1,e2) as pr), Z, (m1,m2), Z, sf) ->
let y =
match sf with
| B3 (f1,f2,f3) ->
Y (B7 (e1,e2,m1,m2,f1,f2,f3))
| _ ->
let f', sf = popBufferL sf in
U (B3 (e1,e2,m1), Z, (m2,f'), Z, sf)
in
Some (x, y)
| U ((B3 _ as pr), ld, mid, rd, sf) ->
let pr, ld, mid, rd, sf = greenLeft pr ld mid rd sf in
Some (popLeftNaive (U (pr, ld, mid, rd, sf)))
| _ ->
assert false
and popRight = function
| Z ->
None
| Y (B1 x) ->
Some (x, Z)
| Y b ->
let x, b = popBufferR b in
Some (x, Y b)
| U (pr, ld, mid, rd, (B4 _ | B5 _ | B6 _ as sf)) ->
let x, sf = popBufferR sf in
Some (x, U (pr, ld, mid, rd, sf))
| U (pr, Z, (m2,m1), Z, (B3 (e2,e1,x) as sf)) ->
let y =
match pr with
| B3 (p3,p2,p1) ->
Y (B7 (p3,p2,p1,m2,m1,e2,e1))
| _ ->
let f', pr = popBufferR pr in
U (pr, Z, (f',m2), Z, B3 (m1,e2,e1))
in
Some (x, y)
| U (pr, ld, mid, rd, (B3 _ as sf)) ->
let pr, ld, mid, rd, sf = greenRight pr ld mid rd sf in
Some (popRightNaive (U (pr, ld, mid, rd, sf)))
| _ ->
assert false
and catenate d1 d2 =
match d1, d2 with
| Z, _ ->
d2
| _, Z ->
d1
| Y b, _ ->
begin
match b with
| B1 x -> pushLeft x d2
| _ -> let x, b = popBufferR b in catenate (Y b) (pushLeft x d2)
end
| _, Y b ->
begin
match b with
| B1 x -> pushRight x d1
| _ -> let x, b = popBufferL b in catenate (pushRight x d1) (Y b)
end
| U (pr1, ld1, mid1, rd1, sf1), U (pr2, ld2, mid2, rd2, sf2) ->
let y, pr2 = popBufferL pr2 and x, sf1 = popBufferR sf1 in
let mid = x, y in
let ld =
let m1,m2 = mid1 in
let pRight = Obj.magic pushRight in
match sf1 with
| B2 _
| B3 _ ->
pRight (T3 (B2 (m1,m2), rd1, sf1)) ld1
| B4 (e1,e2,e3,e4) ->
let ld'1 = pRight (T3 (B2 (m1,m2), rd1, B2 (e1,e2))) ld1 in
pRight (T1 (B2 (e3,e4))) ld'1
| B5 (e1,e2,e3,e4,e5) ->
let s'1 = B3 (e1,e2,e3) in
let ld'1 = pRight (T3 (B2 (m1,m2), rd1, s'1)) ld1 in
pRight (T1 (B2 (e4,e5))) ld'1
| _ ->
assert false
in
let rd =
let m2,m1 = mid2 in
let pLeft = Obj.magic pushLeft in
match pr2 with
| B2 _
| B3 _ ->
pLeft (T3 (pr2, ld2, B2 (m2,m1))) rd2
| B4 (e4,e3,e2,e1) ->
let rd'1 = pLeft (T3 (B2 (e2,e1), ld2, B2 (m2,m1))) rd2 in
pLeft (T1 (B2 (e4,e3))) rd'1
| B5 (e5,e4,e3,e2,e1) ->
let s'1 = B3 (e3,e2,e1) in
let rd'1 = pLeft (T3 (s'1, ld2, B2 (m2,m1))) rd2 in
pLeft (T1 (B2 (e5,e4))) rd'1
| _ ->
assert false
in
U (pr1, ld, mid, rd, sf2)
let nil = Z
module type Direction_T = sig
val push: 'a -> 'a t -> 'a t
val pop: 'a t -> ('a * 'a t) option
end
module A = struct
let push = pushLeft
let pop = popLeft
end
module B = struct
let push = pushRight
let pop = popRight
end
let sprintB ff = function
| B1 a ->
let a = ff a in
Printf.sprintf "%s" a
| B2 (a,b) ->
let a = ff a in
let b = ff b in
Printf.sprintf "%s,%s" a b
| B3 (a,b,c) ->
let a = ff a in
let b = ff b in
let c = ff c in
Printf.sprintf "%s,%s,%s" a b c
| B4 (a,b,c,d) ->
let a = ff a in
let b = ff b in
let c = ff c in
let d = ff d in
Printf.sprintf "%s,%s,%s,%s" a b c d
| B5 (a,b,c,d,e) ->
let a = ff a in
let b = ff b in
let c = ff c in
let d = ff d in
let e = ff e in
Printf.sprintf "%s,%s,%s,%s,%s" a b c d e
| B6 (a,b,c,d,e,f) ->
let a = ff a in
let b = ff b in
let c = ff c in
let d = ff d in
let e = ff e in
let f = ff f in
Printf.sprintf "%s,%s,%s,%s,%s,%s" a b c d e f
| B7 (a,b,c,d,e,f,g) ->
let a = ff a in
let b = ff b in
let c = ff c in
let d = ff d in
let e = ff e in
let f = ff f in
let g = ff g in
Printf.sprintf "%s,%s,%s,%s,%s,%s,%s" a b c d e f g
| B8 (a,b,c,d,e,f,g,h) ->
let a = ff a in
let b = ff b in
let c = ff c in
let d = ff d in
let e = ff e in
let f = ff f in
let g = ff g in
let h = ff h in
Printf.sprintf "%s,%s,%s,%s,%s,%s,%s,%s" a b c d e f g h
let rec sprint f = function
| Z ->
"{}"
| Y b ->
Printf.sprintf "{%s}" (sprintB f b)
| U (pr, ld, (m1,m2), rd, sf) ->
let g = sprintT f in
let pr = sprintB f pr in
let ld = (Obj.magic sprint) g ld in
let mid = sprintB f (B2 (m1,m2)) in
let rd = (Obj.magic sprint) g rd in
let sf = sprintB f sf in
Printf.sprintf "{%s;%s;%s;%s;%s}" pr ld mid rd sf
and sprintT f = function
| T1 b -> Printf.sprintf "<%s>" (sprintB f b)
| T2 (b1,b2) -> Printf.sprintf "(%s/%s)" (sprintB f b1) (sprintB f b2)
| T3 (b1,q,b2) ->
let b1 = sprintB f b1 in
let q = (Obj.magic sprint) (fun x -> sprintT f x) q in
let b2 = sprintB f b2 in
Printf.sprintf "[%s|%s|%s]" b1 q b2
(*--- End of File [ cf_kotdeque.ml ] ---*)
[-- Attachment #3: cf_kotdeque.mli --]
[-- Type: application/octet-stream, Size: 1845 bytes --]
(*---------------------------------------------------------------------------*
INTERFACE cf_kotdeque.mli
Copyright (c) 2003, James H. Woodyatt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*---------------------------------------------------------------------------*)
type 'a t
val nil: 'a t
module type Direction_T = sig
val push: 'a -> 'a t -> 'a t
val pop: 'a t -> ('a * 'a t) option
end
module A: Direction_T
module B: Direction_T
val catenate: 'a t -> 'a t -> 'a t
val sprint: ('a -> string) -> 'a t -> string
(*--- End of File [ cf_kotdeque.mli ] ---*)
[-- Attachment #4: Type: text/plain, Size: 1593 bytes --]
> If I remember, the algorithm was described using nonuniform
> data types, so that's yet another plug for supporting this more
> directly in
> OCaml, meaning, without having to use recursive modules, record field
> polymorphism, or polymorphic records to work around the ability to
> directly write such functions.
The structure uses "bootstrapping" and so does my [Cf_deque] structure.
I have handled bootstrapping in [Cf] with judicious use of [Obj.magic]
to cast functions into the appropriate type at the recursion.
Note: My [Cf] library is loaded with calls to [Obj.magic]. There are
lots of places where the only way I could solve a problem was by
hammering something deeply weird into a shape that would fit into the
Ocaml type system. Mostly, that happens where I have an interface to
C library stuff and I'm using shadow type annotations. But the
bootstrapped data structures are another place. And the [Cf_gadget]
module needs to do something similar (which was well known in the
original Haskell code where that idea started).
Every time the Ocaml team updates the compiler, I'm worried they're
going to change something that invalidates my assumptions about what
[Obj.magic] can and cannot do for me. I'm *not* saying they didn't
warn me. I knew the job was dangerous.
I'd be more exercised about the 'looping recursion' problem with
List.map exploding on large data sets if I were not in the habit of
using my [Cf] structures to avoid all that.
--
j h woodyatt <jhw@wetware.com>
that's my village calling... no doubt, they want their idiot back.
next prev parent reply other threads:[~2004-07-30 18:26 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-07-27 23:43 [Caml-list] looping recursion briand
2004-07-28 0:27 ` John Prevost
2004-07-28 0:38 ` John Prevost
2004-07-28 1:17 ` skaller
2004-07-28 1:05 ` briand
2004-07-28 1:43 ` Brian Hurt
2004-07-28 2:49 ` briand
2004-07-28 3:12 ` Brian Hurt
2004-07-28 3:20 ` Brian Hurt
2004-07-28 5:54 ` brogoff
2004-07-28 7:22 ` Alex Baretta
2004-07-28 16:38 ` brogoff
2004-07-28 19:40 ` Jon Harrop
2004-07-28 20:18 ` Brandon J. Van Every
2004-07-29 6:01 ` Alex Baretta
2004-07-28 21:22 ` brogoff
2004-07-29 9:13 ` Daniel Andor
2004-07-29 9:25 ` Keith Wansbrough
2004-07-29 9:41 ` Nicolas Cannasse
2004-07-29 9:57 ` Xavier Leroy
2004-07-29 10:44 ` Daniel Andor
2004-07-29 12:56 ` brogoff
2004-07-29 10:11 ` skaller
2004-07-29 12:41 ` brogoff
2004-07-29 6:28 ` Alex Baretta
2004-07-29 14:58 ` brogoff
2004-07-29 16:12 ` Brian Hurt
2004-07-29 17:49 ` james woodyatt
2004-07-29 19:25 ` Brian Hurt
2004-07-29 20:01 ` brogoff
2004-07-30 4:42 ` james woodyatt
2004-07-29 17:44 ` james woodyatt
2004-07-29 23:12 ` skaller
2004-07-29 22:42 ` Alex Baretta
2004-07-30 2:38 ` Corey O'Connor
[not found] ` <200407300136.14042.jon@jdh30.plus.com>
2004-07-30 12:45 ` Alex Baretta
2004-07-30 17:07 ` brogoff
2004-07-30 18:25 ` james woodyatt [this message]
2004-07-30 21:20 ` [Caml-list] kaplan-okasaki-tarjan deque (was "looping recursion") brogoff
2004-07-31 5:37 ` james woodyatt
2004-07-28 7:27 ` [Caml-list] looping recursion skaller
2004-07-28 14:36 ` Brian Hurt
2004-07-28 22:05 ` skaller
2004-07-28 0:37 ` skaller
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=E6358338-E255-11D8-995D-000A958FF2FE@wetware.com \
--to=jhw@wetware.com \
--cc=brogoff@speakeasy.net \
--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).