Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
* [Caml-list] Reading a large text file
@ 2004-04-28 15:28 André Luiz Moura
  2004-04-28 16:28 ` Richard Jones
  2004-05-01 14:03 ` Brian Hurt
  0 siblings, 2 replies; 27+ messages in thread
From: André Luiz Moura @ 2004-04-28 15:28 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 648 bytes --]

Hi List, 
 
I wrote an OCaml function to read a text file with a million of lines with  five separate columns for spaces. I based myself on previous messages of Caml-list, but however the work is taking time frightful (many minutes). 
This function written in C, for example, does not take more than 4 seconds. 
 
I am executing the program in a PC Pentium III of 128 MB of RAM under Windows platform. How would be implemented the function to decide this problem?

File format:
<vertex #> <x> <y> [attributes] [boundary marker] 

Thanks, 

André






---------------------------------
Yahoo! Messenger - Fale com seus amigos online. Instale agora!

[-- Attachment #2: Type: text/html, Size: 974 bytes --]

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

* Re: [Caml-list] Reading a large text file
  2004-04-28 15:28 [Caml-list] Reading a large text file André Luiz Moura
@ 2004-04-28 16:28 ` Richard Jones
  2004-05-01 14:03 ` Brian Hurt
  1 sibling, 0 replies; 27+ messages in thread
From: Richard Jones @ 2004-04-28 16:28 UTC (permalink / raw)
  Cc: caml-list

On Wed, Apr 28, 2004 at 12:28:13PM -0300, Andr? Luiz Moura wrote:
> Hi List, 
>  
> I wrote an OCaml function to read a text file with a million of lines with  five separate columns for spaces. I based myself on previous messages of Caml-list, but however the work is taking time frightful (many minutes). 
> This function written in C, for example, does not take more than 4 seconds. 
>  
> I am executing the program in a PC Pentium III of 128 MB of RAM under Windows platform. How would be implemented the function to decide this problem?
> 
> File format:
> <vertex #> <x> <y> [attributes] [boundary marker] 

Post some example code?

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
NET::FTPSERVER is a full-featured, secure, configurable, database-backed
FTP server written in Perl: http://www.annexia.org/freeware/netftpserver/

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-04-28 15:28 [Caml-list] Reading a large text file André Luiz Moura
  2004-04-28 16:28 ` Richard Jones
@ 2004-05-01 14:03 ` Brian Hurt
  2004-05-01 15:43   ` Rahul Siddharthan
  2004-05-17  5:28   ` Eric Stokes
  1 sibling, 2 replies; 27+ messages in thread
From: Brian Hurt @ 2004-05-01 14:03 UTC (permalink / raw)
  To: André Luiz Moura; +Cc: caml-list


I'm still digging through a serious backlog of email, so your question may 
have already been answered.  If so, ignore this.

But what I'm guessing is happening is that you are appending (adding to 
the end of) your list, and that this is what is killing you.  To add an 
element to the *end* of a list, Ocaml has to completely reallocate the 
entire list- turning what you might think is an O(1) operation into an 
O(n) operation.

The solution to this is to build the list backwards- instead of adding 
things to the end of the list, add them to the begining.  Then, when 
you're done, just reverse the list using List.rev.

Lets look at the example of just reading the lines from a file and making 
a list of them.  This code is bad:

let readfile chan =
    let rec loop lst =
        try
            loop (lst @ [ (input_line chan) ])
        with
            | End_of_file -> lst
    in
    loop []
;;

It works, but to read n lines requires O(n^2) work, because the @ has to
reallocate the entire list every iteration.  Worse yet it isn't tail
recursive (a recursive call inside a try/catch isn't a tail call).

A better implementation of this would be:
let readfile chan =
    let rec loop rlst =
       let line, eof = 
           try
               (input_line chan), false
           with
               | End_of_file -> "", true
       in
       if not eof then
           loop (line :: rlst)
       else
           List.rev rlst
   in
   loop []
;;

Now, the first thing to notice is that we're using the :: operator (which
is O(1)), not the @ operator (which is O(n))- we're prepending things onto
the list, not appending them.  We're building up the list backwards, and
then, when we hit the end of the file, reversing the entire list.  This is
a standard pattern in Ocaml.

The second thing to notice is that the recursive call has been hoisted up 
out of the try/catch block.  We've introduced a new boolean flag to note 
when we've hit the end of the file- catching the exception simply sets the 
flag to true.  So now our function is tail recursive, and operates in 
constant stack space.

Brian

On Wed, 28 Apr 2004, André Luiz Moura wrote:

> Hi List, 
>  
> I wrote an OCaml function to read a text file with a million of lines with  five separate columns for spaces. I based myself on previous messages of Caml-list, but however the work is taking time frightful (many minutes). 
> This function written in C, for example, does not take more than 4 seconds. 
>  
> I am executing the program in a PC Pentium III of 128 MB of RAM under Windows platform. How would be implemented the function to decide this problem?
> 
> File format:
> <vertex #> <x> <y> [attributes] [boundary marker] 
> 
> Thanks, 
> 
> André
> 
> 
> 
> 
> 
> 
> ---------------------------------
> Yahoo! Messenger - Fale com seus amigos online. Instale agora!

-- 
"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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 14:03 ` Brian Hurt
@ 2004-05-01 15:43   ` Rahul Siddharthan
  2004-05-01 16:00     ` [Caml-list] [OcamlDoc] langage support sejourne kevin
  2004-05-01 18:05     ` [Caml-list] Reading a large text file Richard Jones
  2004-05-17  5:28   ` Eric Stokes
  1 sibling, 2 replies; 27+ messages in thread
From: Rahul Siddharthan @ 2004-05-01 15:43 UTC (permalink / raw)
  To: Brian Hurt; +Cc: Andr? Luiz Moura, caml-list

Brian Hurt said on May  1, 2004 at 09:03:56:
> But what I'm guessing is happening is that you are appending (adding to 
> the end of) your list, and that this is what is killing you.  To add an 
> element to the *end* of a list, Ocaml has to completely reallocate the 
> entire list- turning what you might think is an O(1) operation into an 
> O(n) operation.

I'm pretty puzzled by that: why would it have to do that?  Arrays,
yes, but lists, can't it just traverse the existing list to its end
and then add a new element?  It's still O(n) but no reallocation.

> The solution to this is to build the list backwards- instead of adding 
> things to the end of the list, add them to the begining.  Then, when 
> you're done, just reverse the list using List.rev.

Yes that seems best.

Rahul

-------------------
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] 27+ messages in thread

* [Caml-list] [OcamlDoc] langage support.
  2004-05-01 15:43   ` Rahul Siddharthan
@ 2004-05-01 16:00     ` sejourne kevin
  2004-05-14  7:15       ` Maxence Guesdon
  2004-05-01 18:05     ` [Caml-list] Reading a large text file Richard Jones
  1 sibling, 1 reply; 27+ messages in thread
From: sejourne kevin @ 2004-05-01 16:00 UTC (permalink / raw)
  To: caml-list

Hi evrybody!

Is there a way in Ocamldoc to make multilingual
documentation ? I think of something like that :

(**
	[En] Reverse a list.
	[Fr] Retourne une liste.
	[Es] ...
*)
Let rev = List.rev ;;

And generate documentation file in evry langage use in
the code?

Kevin


	

	
		
Yahoo! Mail : votre e-mail personnel et gratuit qui vous suit partout ! 
Créez votre Yahoo! Mail sur http://fr.benefits.yahoo.com/

Dialoguez en direct avec vos amis grâce à Yahoo! Messenger !Téléchargez Yahoo! Messenger sur http://fr.messenger.yahoo.com

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 15:43   ` Rahul Siddharthan
  2004-05-01 16:00     ` [Caml-list] [OcamlDoc] langage support sejourne kevin
@ 2004-05-01 18:05     ` Richard Jones
  2004-05-01 18:25       ` Charles Forsyth
  2004-05-01 19:25       ` skaller
  1 sibling, 2 replies; 27+ messages in thread
From: Richard Jones @ 2004-05-01 18:05 UTC (permalink / raw)
  Cc: caml-list

On Sat, May 01, 2004 at 11:43:51AM -0400, Rahul Siddharthan wrote:
> Brian Hurt said on May  1, 2004 at 09:03:56:
> > But what I'm guessing is happening is that you are appending (adding to 
> > the end of) your list, and that this is what is killing you.  To add an 
> > element to the *end* of a list, Ocaml has to completely reallocate the 
> > entire list- turning what you might think is an O(1) operation into an 
> > O(n) operation.
> 
> I'm pretty puzzled by that: why would it have to do that?  Arrays,
> yes, but lists, can't it just traverse the existing list to its end
> and then add a new element?  It's still O(n) but no reallocation.

The short answer is no, because in OCaml (unlike in LISP) lists are
immutable.  In LISP terminology, there's no way to 'set cdr' on an
OCaml 'cons structure'.  The disadvantage to this is that you can't do
certain destructive operations on lists, like you can so easily in
LISP.  The advantage is that you can't do certain destructive
operations on lists!  In other words, your code is more likely to be
bug free.

However, OCaml is a practical language and so allows you to create a
mutable cons structure if you so desire.  eg:

# type 'a mylist = { head : 'a; mutable tail : 'a mylist option };;
type 'a mylist = { head : 'a; mutable tail : 'a mylist option; }

# let xs = { head = 10; tail = None };;
val xs : int mylist = {head = 10; tail = None}
# let xs = { head = 5; tail = Some xs};;
val xs : int mylist = {head = 5; tail = Some {head = 10; tail = None}}

# let ys = { head = 20; tail = None };;		(* new tail *)
val ys : int mylist = {head = 20; tail = None}

# xs.tail <- Some ys;;				(* replace tail of xs *)
- : unit = ()
# xs;;
- : int mylist = {head = 5; tail = Some {head = 20; tail = None}}

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
MAKE+ is a sane replacement for GNU autoconf/automake. One script compiles,
RPMs, pkgs etc. Linux, BSD, Solaris. http://www.annexia.org/freeware/makeplus/

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 18:05     ` [Caml-list] Reading a large text file Richard Jones
@ 2004-05-01 18:25       ` Charles Forsyth
  2004-05-01 19:25       ` skaller
  1 sibling, 0 replies; 27+ messages in thread
From: Charles Forsyth @ 2004-05-01 18:25 UTC (permalink / raw)
  To: caml-list

>>The short answer is no, because in OCaml (unlike in LISP) lists are
>>immutable.  In LISP terminology, there's no way to 'set cdr' on an
>>OCaml 'cons structure'.  The disadvantage to this is that you can't do
>>certain destructive operations on lists, like you can so easily in
>>LISP.  The advantage is that you can't do certain destructive
>>operations on lists!  In other words, your code is more likely to be
>>bug free.

the concurrent programming language Limbo does much the same,
and has a similar penalty for appending to a list.  nevertheless, it has
advantages as you say, and i thought i'd add that the property
turns out to be quite helpful in concurrent programs, because you
can pass another process the current value of a list (for instance by sending
it on a channel) and be sure it always sees the `right' value.
i've found it particularly useful for lock-free concurrent access to caches
implemented by hash tables (array of list of T), when the cache
acts as a hint (as for instance in DNS implementation).
as you say, you can always program a mutable list when you need one.

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 18:05     ` [Caml-list] Reading a large text file Richard Jones
  2004-05-01 18:25       ` Charles Forsyth
@ 2004-05-01 19:25       ` skaller
  2004-05-01 19:51         ` Alain.Frisch
  1 sibling, 1 reply; 27+ messages in thread
From: skaller @ 2004-05-01 19:25 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

On Sun, 2004-05-02 at 04:05, Richard Jones wrote:
> On Sat, May 01, 2004 at 11:43:51AM -0400, Rahul Siddharthan wrote:

> The short answer is no, because in OCaml (unlike in LISP) lists are
> immutable. 

> However, OCaml is a practical language and so allows you to create a
> mutable cons structure if you so desire.  eg:

It can now do slightly better than that. It is possible to use
the new 'private' keyword to *guard* your mutable list.

module MList = struct 
type 'a mylist = private { head : 'a; mutable tail : 'a mylist option; }
..
let splice a b = ...(* makes a new mylist of a @ b *)
end

Here, lists are immutable *publically*. However the splice
function provides a concatenation of two ordinary lists
into a mylist in 1 pass, with O(1) stack usage <grin>
and the result is in forward order, not reversed.

The list is still immutable! You can't modify it.
The mutable field is only used during construction
to append to the end, preserving the forward ordering.

Its possible for C language implementations to do
that kind of thing right now for actual Ocaml lists.
But now you can play the game in Ocaml.

-- 
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 19:25       ` skaller
@ 2004-05-01 19:51         ` Alain.Frisch
  2004-05-01 20:40           ` skaller
  0 siblings, 1 reply; 27+ messages in thread
From: Alain.Frisch @ 2004-05-01 19:51 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

On 2 May 2004, skaller wrote:

> It can now do slightly better than that. It is possible to use
> the new 'private' keyword to *guard* your mutable list.
>
> module MList = struct
> type 'a mylist = private { head : 'a; mutable tail : 'a mylist option; }
> ..
> let splice a b = ...(* makes a new mylist of a @ b *)
> end
> Here, lists are immutable *publically*.

Not quite.

First, the "private" keyword should be used only in the signature, not the
structure, otherwise the implementation of the module has no special
right. Something like:

module M :
 sig type t = private *** end
=
 struct type t = *** end

Second, the client cannot create values of the "private" type.  This is
not related at all with the mutability of the fields. It can only
deconstruct values (with pattern matching). So you have to expose
constructors explicitly (splice is one of them, but you probably want a
simple Cons).


-- Alain

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 19:51         ` Alain.Frisch
@ 2004-05-01 20:40           ` skaller
  2004-05-01 21:11             ` [Caml-list] Private types skaller
  2004-05-01 21:33             ` [Caml-list] Reading a large text file Alain.Frisch
  0 siblings, 2 replies; 27+ messages in thread
From: skaller @ 2004-05-01 20:40 UTC (permalink / raw)
  To: Alain.Frisch; +Cc: caml-list

On Sun, 2004-05-02 at 05:51, Alain.Frisch@ens.fr wrote:
> On 2 May 2004, skaller wrote:
> 
> > It can now do slightly better than that. It is possible to use
> > the new 'private' keyword to *guard* your mutable list.
> >
> > module MList = struct
> > type 'a mylist = private { head : 'a; mutable tail : 'a mylist option; }
> > ..
> > let splice a b = ...(* makes a new mylist of a @ b *)
> > end
> > Here, lists are immutable *publically*.
> 
> Not quite.
> 
> First, the "private" keyword should be used only in the signature, not the
> structure, otherwise the implementation of the module has no special
> right. Something like:
> 
> module M :
>  sig type t = private *** end
> =
>  struct type t = *** end

Thanks for the correction. Also note I chose a *really bad name*
when I called it 'splice': the intent was to construct
a new list as stated, so I should have just called it 'concat'.

Of course you could make a list with an actual splice mutator,
but then it wouldn't be immutable.

> Second, the client cannot create values of the "private" type.  This is
> not related at all with the mutability of the fields. It can only
> deconstruct values (with pattern matching). 

Right. Well stated.

Hmm ..

 module M : sig
  ?? type 'a t = private 'a list
    val uniq_cons: 'a t -> 'a -> 'a list
    val empty: unit -> 'a list
  end = struct
    type 'a t = 'a list
    let uniq_cons lst a = if List.mem a lst then lst else a::lst
    let empty () = []
  end
  ;;              ;;
Syntax error: 'end' expected, the highlighted 'sig' might be unmatched

Arggg.. what's wrong here? It has nothing to do with
either private or type variables, and the above sig
fails immediately in a module type statement too.

-- 
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] 27+ messages in thread

* [Caml-list] Private types
  2004-05-01 20:40           ` skaller
@ 2004-05-01 21:11             ` skaller
  2004-05-01 21:33             ` [Caml-list] Reading a large text file Alain.Frisch
  1 sibling, 0 replies; 27+ messages in thread
From: skaller @ 2004-05-01 21:11 UTC (permalink / raw)
  To: caml-list

Ahh, well this works:

module type M_t = sig
type 'a t = private { x: 'a list }
val uniq_cons: 'a t -> 'a -> 'a t
val empty: unit -> 'a t
end
 
module M : M_t = struct
type 'a t = { x : 'a list }
let uniq_cons lst a = if List.mem a lst.x then lst else { x = a::lst.x }
let empty () = { x = [] }
end
 
let x = M.empty ()
let x = M.uniq_cons x 1
let x = M.uniq_cons x 1
let x = M.uniq_cons x 2
 
let print { M.x=x } = print_endline (
  "[" ^
  String.concat "," (List.map string_of_int x) ^
  "]"
)
;;                                                                            print x
;;

[skaller@pelican] /mnt/user2/work/flx>ocaml xx.ml
[2,1]

-- 
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 20:40           ` skaller
  2004-05-01 21:11             ` [Caml-list] Private types skaller
@ 2004-05-01 21:33             ` Alain.Frisch
  1 sibling, 0 replies; 27+ messages in thread
From: Alain.Frisch @ 2004-05-01 21:33 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

On 2 May 2004, skaller wrote:

>   ?? type 'a t = private 'a list
>
> Arggg.. what's wrong here?

As stated in the manual, "private" can only be applied to the type
*representation* (sum type, record type), not the type equation.

http://caml.inria.fr/ocaml/htmlman/manual021.html

-- Alain

-------------------
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] 27+ messages in thread

* Re: [Caml-list] [OcamlDoc] langage support.
  2004-05-01 16:00     ` [Caml-list] [OcamlDoc] langage support sejourne kevin
@ 2004-05-14  7:15       ` Maxence Guesdon
  0 siblings, 0 replies; 27+ messages in thread
From: Maxence Guesdon @ 2004-05-14  7:15 UTC (permalink / raw)
  To: sejourne kevin, caml-list

On Sat, 1 May 2004 18:00:24 +0200 (CEST)
sejourne kevin <sejourne_kevin@yahoo.fr> wrote:

> Hi evrybody!
> 
> Is there a way in Ocamldoc to make multilingual
> documentation ? I think of something like that :
> 
> (**
> 	[En] Reverse a list.
> 	[Fr] Retourne une liste.
> 	[Es] ...
> *)
> Let rev = List.rev ;;
> 
> And generate documentation file in evry langage use in
> the code?

No there is no such feature. You can add it yourself in a custom
generator by handling @fr, @en, @es, ..., tags.

Hope this helps,

-- 
Maxence Guesdon

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Reading a large text file
  2004-05-01 14:03 ` Brian Hurt
  2004-05-01 15:43   ` Rahul Siddharthan
@ 2004-05-17  5:28   ` Eric Stokes
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Stokes @ 2004-05-17  5:28 UTC (permalink / raw)
  To: André Luiz Moura; +Cc: caml-list

If you don't care about line breaks you might try Buffer.add_channel. 
This should perform
close to O(1) for the append operations, and it will bypass the call to 
input_line, which I have
found to be an order of magnitude slower than the read system call. You 
can always break
the lines up later.

On May 1, 2004, at 7:03 AM, Brian Hurt wrote:

>
> I'm still digging through a serious backlog of email, so your question 
> may
> have already been answered.  If so, ignore this.
>
> But what I'm guessing is happening is that you are appending (adding to
> the end of) your list, and that this is what is killing you.  To add an
> element to the *end* of a list, Ocaml has to completely reallocate the
> entire list- turning what you might think is an O(1) operation into an
> O(n) operation.
>
> The solution to this is to build the list backwards- instead of adding
> things to the end of the list, add them to the begining.  Then, when
> you're done, just reverse the list using List.rev.
>
> Lets look at the example of just reading the lines from a file and 
> making
> a list of them.  This code is bad:
>
> let readfile chan =
>     let rec loop lst =
>         try
>             loop (lst @ [ (input_line chan) ])
>         with
>             | End_of_file -> lst
>     in
>     loop []
> ;;
>
> It works, but to read n lines requires O(n^2) work, because the @ has 
> to
> reallocate the entire list every iteration.  Worse yet it isn't tail
> recursive (a recursive call inside a try/catch isn't a tail call).
>
> A better implementation of this would be:
> let readfile chan =
>     let rec loop rlst =
>        let line, eof =
>            try
>                (input_line chan), false
>            with
>                | End_of_file -> "", true
>        in
>        if not eof then
>            loop (line :: rlst)
>        else
>            List.rev rlst
>    in
>    loop []
> ;;
>
> Now, the first thing to notice is that we're using the :: operator 
> (which
> is O(1)), not the @ operator (which is O(n))- we're prepending things 
> onto
> the list, not appending them.  We're building up the list backwards, 
> and
> then, when we hit the end of the file, reversing the entire list.  
> This is
> a standard pattern in Ocaml.
>
> The second thing to notice is that the recursive call has been hoisted 
> up
> out of the try/catch block.  We've introduced a new boolean flag to 
> note
> when we've hit the end of the file- catching the exception simply sets 
> the
> flag to true.  So now our function is tail recursive, and operates in
> constant stack space.
>
> Brian
>
> On Wed, 28 Apr 2004, André Luiz Moura wrote:
>
>> Hi List,
>>
>> I wrote an OCaml function to read a text file with a million of lines 
>> with  five separate columns for spaces. I based myself on previous 
>> messages of Caml-list, but however the work is taking time frightful 
>> (many minutes).
>> This function written in C, for example, does not take more than 4 
>> seconds.
>>
>> I am executing the program in a PC Pentium III of 128 MB of RAM under 
>> Windows platform. How would be implemented the function to decide 
>> this problem?
>>
>> File format:
>> <vertex #> <x> <y> [attributes] [boundary marker]
>>
>> Thanks,
>>
>> André
>>
>>
>>
>>
>>
>>
>> ---------------------------------
>> Yahoo! Messenger - Fale com seus amigos online. Instale agora!
>
> -- 
> "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
>

-------------------
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] 27+ messages in thread

* Re: [Caml-list] Private types
  2008-11-01 20:18             ` David Allsopp
@ 2008-11-02 14:53               ` Edgar Friendly
  0 siblings, 0 replies; 27+ messages in thread
From: Edgar Friendly @ 2008-11-02 14:53 UTC (permalink / raw)
  To: David Allsopp, caml-list

David Allsopp wrote:
> I agree that the error will still show up somewhere if there is an error -
> but remember that a closed polymorphic variant type required an annotation
> in the first place (in this case, the type [t] and the explicit type
> annotation to use it)... so having made the explicit choice to declare the
> type closed (which you either do to declare module interfaces or to try to
> trap errors) the last thing (I'd say!) you want is the compiler trying to
> open them back up on every unification failure!
> 
> 
> David
> 
You only declared the argument to the function as closed.  This doesn't
mean that the return type of the function must be that closed type.  If
you declared the function as returning type t, then the auto-open would
run into a type roadblock before it left the function.  But given your
initial code, the intent of the programmer seems clear in wanting a
different return type.

E.


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

* RE: [Caml-list] Private types
  2008-11-01 19:31           ` Edgar Friendly
@ 2008-11-01 20:18             ` David Allsopp
  2008-11-02 14:53               ` Edgar Friendly
  0 siblings, 1 reply; 27+ messages in thread
From: David Allsopp @ 2008-11-01 20:18 UTC (permalink / raw)
  To: 'Edgar Friendly'; +Cc: 'Jacques Garrigue', caml-list

Edgar Friendly wrote:
> David Allsopp wrote:
>
> > Without the full coercion for x you'll get a type error because the type
> > checker infers that the type of the [if] expression is [t] from the
> > [then] branch and then fails to unify [> `B of int ] with [t] unless the
> > type of [x] is first coerced to [> t ]. If the compiler were to try (x :
> > t : [> t ]) in all those instances I think that would render polymorphic
> > variants pretty unusable ... the type checker needs to know that you
> > meant to do that or everything will unify!
> 
> Okay, you claim we shouldn't automatically open polymorphic variants.  I
> don't see why auto->ing polymorphic types is really a problem.  If the
> later code (receiving the returned value) can't handle the [> ] type,
> that type error will stop things (although it won't point out where the
> [> ] came from).  This seems one case where the compiler can easily DWIM
> the correct result.

I agree that the error will still show up somewhere if there is an error -
but remember that a closed polymorphic variant type required an annotation
in the first place (in this case, the type [t] and the explicit type
annotation to use it)... so having made the explicit choice to declare the
type closed (which you either do to declare module interfaces or to try to
trap errors) the last thing (I'd say!) you want is the compiler trying to
open them back up on every unification failure!


David


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

* Re: [Caml-list] Private types
  2008-11-01 10:00         ` Jacques Garrigue
@ 2008-11-01 19:41           ` Edgar Friendly
  0 siblings, 0 replies; 27+ messages in thread
From: Edgar Friendly @ 2008-11-01 19:41 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: dra-news, caml-list

Jacques Garrigue wrote:
> If we limit ourselves to the case where both [x] and [y] contrain no
> type variables, this si not particularly difficult. However whether
> they will contain type variables or not depends heavily on how the
> type inference algorithm proceeds.
> 
> If they contain type variables, then the situation becomes much more
> muddled, as these type variables may get instantiated by the subtyping
> check, and not necessarily as expected. So typing becomes rather
> unpredictable...
> 
>      Jacques Garrigue

We've reached the end of my intuition - I admit I get stuck thinking
about automatic casts with type variables.  I can only point out that
for an appropriate definition of "expected" (as in "found type x but
expected type y"), one will always get the expected type.  :)

If the line in the sand has to be drawn somewhere (between
auto-subtyping and not), this seems a simple and effective place to do so.

E.


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

* Re: [Caml-list] Private types
  2008-11-01  8:19         ` David Allsopp
@ 2008-11-01 19:31           ` Edgar Friendly
  2008-11-01 20:18             ` David Allsopp
  0 siblings, 1 reply; 27+ messages in thread
From: Edgar Friendly @ 2008-11-01 19:31 UTC (permalink / raw)
  To: David Allsopp; +Cc: 'Jacques Garrigue', caml-list

David Allsopp wrote:

> Without the full coercion for x you'll get a type error because the type
> checker infers that the type of the [if] expression is [t] from the [then]
> branch and then fails to unify [> `B of int ] with [t] unless the type of
> [x] is first coerced to [> t ]. If the compiler were to try (x : t : [> t ])
> in all those instances I think that would render polymorphic variants pretty
> unusable ... the type checker needs to know that you meant to do that or
> everything will unify!
> 
Okay, you claim we shouldn't automatically open polymorphic variants.  I
don't see why auto->ing polymorphic types is really a problem.  If the
later code (receiving the returned value) can't handle the [> ] type,
that type error will stop things (although it won't point out where the
[> ] came from).  This seems one case where the compiler can easily DWIM
the correct result.

>> Would it be particularly difficult to, in the cases where type [x] is
>> found but type [y] is expected, to try a (foo : x :> y) cast?
> 
> +1! With reference my previous comment that "the type checker needs to know
> if you meant that", there's still the option of using fully abstract types
> if you wanted to avoid this kind of automatic coercion and have, say,
> positive integers totally distinct from all integers without an explicit
> cast.
> 
Actually, I do see the use of two kinds of derived types:
type positive = private int ( auto-coerced to int )
type category_id = new int (not auto-coerced to int - math not allowed)

I assume there's some efficiency benefit to exposing the underlying type
of category_id, if not then abstract types will quite suffice.

> All said, I do see Jacques point of wanting to keep coercion and type
> inference totally separate... though perhaps if coercions were only tried
> during unification if at least one of the types in question is private that
> would maintain a certain level of predictability about when they're used
> automatically?
> 
> 
> David
> 
I'm happy moving down this slope of the compiler doing more of the work.
 Hopefully it's slippery, so it'll end up doing lots of work for me.

E.


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

* Re: [Caml-list] Private types
  2008-11-01  1:52       ` Edgar Friendly
  2008-11-01  8:19         ` David Allsopp
@ 2008-11-01 10:00         ` Jacques Garrigue
  2008-11-01 19:41           ` Edgar Friendly
  1 sibling, 1 reply; 27+ messages in thread
From: Jacques Garrigue @ 2008-11-01 10:00 UTC (permalink / raw)
  To: thelema314; +Cc: dra-news, caml-list

From: Edgar Friendly <thelema314@gmail.com>

> > So the current approach is to completely separate subtyping and type
> > inference, and require coercions everywhere subtyping is needed.
> > 
> Would it be particularly difficult to, in the cases where type [x] is
> found but type [y] is expected, to try a (foo : x :> y) cast?

If we limit ourselves to the case where both [x] and [y] contrain no
type variables, this si not particularly difficult. However whether
they will contain type variables or not depends heavily on how the
type inference algorithm proceeds.

If they contain type variables, then the situation becomes much more
muddled, as these type variables may get instantiated by the subtyping
check, and not necessarily as expected. So typing becomes rather
unpredictable...

> > You can also compare that to the situation between int and float.
> > For most uses, int can be viewed as a subtype of float. However ocaml
> > separates the two, and requires coercion functions whenever you want
> > to use an int as a float.
> > 
> Code isn't produced by a :> cast.  As the internal representation of int
> and float differs, a coercion function isn't required.  The internal
> representation of [private int] and [int] is the same, not to mention
> one is exactly the [private] of the other.

This was not intended as a complete comparison :-)
However, since the coercion function is canonical, I don't think that
this difference matters much here.

     Jacques Garrigue


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

* Re: [Caml-list] Private types
  2008-10-31 14:05       ` Dario Teixeira
@ 2008-11-01  9:52         ` Jacques Garrigue
  0 siblings, 0 replies; 27+ messages in thread
From: Jacques Garrigue @ 2008-11-01  9:52 UTC (permalink / raw)
  To: darioteixeira; +Cc: dra-news, caml-list

Dear Dario,

Since you use a private abbreviation, extraction from the private type
must be explicit before you can do anything on its representation.
So the solution is simple enough:

module Mymod =
  struct
    let is_foo2 x =
      match (x : _ Foobar.t :> [> ]) with `A -> true | `B -> false
  end

The [> ] as target type just says that you expect a polymorphic
variant, which is incompatible with Foobar.t, and triggers its
expansion.

If you want to avoid this explicit coercion, you must use a private
row type in place of a private abbreviation. However, you loose the
ability to distinguish between values created by make_a and make_b at
the type level.

module Foobar: sig
  type foo_t = [ `A ]
  type bar_t = [ `B ]
  type foobar_t = [ foo_t | bar_t ]
  type t = private [< foobar_t]

  val make_a: unit -> t
  val make_b: unit -> t
  val is_foo: t -> bool
  val is_bar: t -> bool
end = struct
  type foo_t = [ `A ]
  type bar_t = [ `B ]
  type foobar_t = [ foo_t | bar_t ]
  type t = foobar_t

  let make_a () = `A
  let make_b () = `B
  let is_foo = function `A -> true | `B -> false
  let is_bar = function `B -> true | `A -> false
end

You may recover this distinction by adding an extra parameter to t,
just as in your original code.

  type 'a t = private [< foobar_t]

but since you won't be able to relate it directly to the expansion of
the type (the row variable is quantified at the module level, so you
cannot capture it with 'a), you would have to recover it by hand.

Jacques Garrigue

> I have also been playing with 3.11's private types, and I would like to
> share a problem I've come across.  Suppose I have a Foobar module defined
> as follows (note the use of a type constraint):
> 
> 
> module Foobar:
> sig
> 	type foo_t = [ `A ]
> 	type bar_t = [ `B ]
> 	type foobar_t = [ foo_t | bar_t ]
> 	type 'a t = 'a constraint 'a = [< foobar_t ]
> 
> 	val make_a: unit -> foo_t t
> 	val make_b: unit -> bar_t t
> 	val is_foo: [< foobar_t] t -> bool
> 	val is_bar: [< foobar_t] t -> bool
> end =
> struct
> 	type foo_t = [ `A ]
> 	type bar_t = [ `B ]
> 	type foobar_t = [ foo_t | bar_t ]
> 	type 'a t = 'a constraint 'a = [< foobar_t ]
> 
> 	let make_a () = `A
> 	let make_b () = `B
> 	let is_foo = function `A -> true | `B -> false
> 	let is_bar = function `B -> true | `A -> false
> end
> 
> 
> Suppose also that I want to define a "is_foo" function in an external module.
> This function only needs to pattern-match on Foobar.t values.  The following
> code will work:
> 
> module Mymod:
> sig
> 	open Foobar
> 
> 	val is_foo2: [< foobar_t] t -> bool
> end =
> struct
> 	let is_foo2 = function `A -> true | `B -> false
> end
> 
> 
> But now consider that I want to enforce the creation of Foobar.t values only
> via Foobar's constructor functions, but I would like to keep the possibility of
> external modules to pattern-match on Foobar.t values.  In other words, change
> Foobar but don't break Mymod.  The immediate (naïve) solution is to make
> use of private types, thus changing the signature of Foobar to the following:
> 
> 
> module Foobar:
> sig
> 	type foo_t = [ `A ]
> 	type bar_t = [ `B ]
> 	type foobar_t = [ foo_t | bar_t ]
> 	type 'a t = private 'a constraint 'a = [< foobar_t ]
> 
> 	val make_a: unit -> foo_t t
> 	val make_b: unit -> bar_t t
> 	val is_foo: [< foobar_t] t -> bool
> 	val is_bar: [< foobar_t] t -> bool
> end = (...)
> 
> 
> But this will break Mymod.  The compile will complain with the following error:
> 
>       Values do not match:
>          val is_foo2 : [< `A | `B ] -> bool
>        is not included in
>          val is_foo2 : [< Foobar.foobar_t ] Foobar.t -> bool
> 
> Any ideas on how can I get around this problem?
> 
> Thanks!
> Cheers,
> Dario Teixeira


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

* RE: [Caml-list] Private types
  2008-11-01  1:52       ` Edgar Friendly
@ 2008-11-01  8:19         ` David Allsopp
  2008-11-01 19:31           ` Edgar Friendly
  2008-11-01 10:00         ` Jacques Garrigue
  1 sibling, 1 reply; 27+ messages in thread
From: David Allsopp @ 2008-11-01  8:19 UTC (permalink / raw)
  To: 'Edgar Friendly', 'Jacques Garrigue'; +Cc: caml-list

Edgar Friendly wrote:
> Jacques Garrigue wrote:
>
> > Your intuition is correct that it would theoretically be possible to
> > try subtyping in place of unification in some cases. The trouble is
> > that thoses cases are not easy to specify (so that it would be hard
> > for the programmer to known when he can remove a coercion), 
>
> Does the compiler really get any information from an explicit cast that
> it can't figure out already?  I can't come up with any example.

Polymorphic variants. Consider:

type t = [ `A of int ]

let f (x : t) =
  let `A n = x
  in
    if n mod 2 = 0
    then (x : t :> [> t ])
    else `B (2 * n)

Without the full coercion for x you'll get a type error because the type
checker infers that the type of the [if] expression is [t] from the [then]
branch and then fails to unify [> `B of int ] with [t] unless the type of
[x] is first coerced to [> t ]. If the compiler were to try (x : t : [> t ])
in all those instances I think that would render polymorphic variants pretty
unusable ... the type checker needs to know that you meant to do that or
everything will unify!

> > So the current approach is to completely separate subtyping and type
> > inference, and require coercions everywhere subtyping is needed.
> > 
> Would it be particularly difficult to, in the cases where type [x] is
> found but type [y] is expected, to try a (foo : x :> y) cast?

+1! With reference my previous comment that "the type checker needs to know
if you meant that", there's still the option of using fully abstract types
if you wanted to avoid this kind of automatic coercion and have, say,
positive integers totally distinct from all integers without an explicit
cast.

All said, I do see Jacques point of wanting to keep coercion and type
inference totally separate... though perhaps if coercions were only tried
during unification if at least one of the types in question is private that
would maintain a certain level of predictability about when they're used
automatically?


David


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

* Re: [Caml-list] Private types
  2008-10-31  0:08     ` Jacques Garrigue
  2008-10-31 14:05       ` Dario Teixeira
@ 2008-11-01  1:52       ` Edgar Friendly
  2008-11-01  8:19         ` David Allsopp
  2008-11-01 10:00         ` Jacques Garrigue
  1 sibling, 2 replies; 27+ messages in thread
From: Edgar Friendly @ 2008-11-01  1:52 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: dra-news, caml-list

Jacques Garrigue wrote:

> Your intuition is correct that it would theoretically be possible to
> try subtyping in place of unification in some cases. The trouble is
> that thoses cases are not easy to specify (so that it would be hard
> for the programmer to known when he can remove a coercion), 

Does the compiler really get any information from an explicit cast that
it can't figure out already?  I can't come up with any example.

> and that
> subtyping is potentially very costly (structural subtyping is much
> harder to check than the nominal subtyping you have in Java.)

As the compiler needs to check that explicit casts are valid, I don't
see any performance difference between explicit and implicit subtype casts.

> So the current approach is to completely separate subtyping and type
> inference, and require coercions everywhere subtyping is needed.
> 
Would it be particularly difficult to, in the cases where type [x] is
found but type [y] is expected, to try a (foo : x :> y) cast?

> You can also compare that to the situation between int and float.
> For most uses, int can be viewed as a subtype of float. However ocaml
> separates the two, and requires coercion functions whenever you want
> to use an int as a float.
> 
Code isn't produced by a :> cast.  As the internal representation of int
and float differs, a coercion function isn't required.  The internal
representation of [private int] and [int] is the same, not to mention
one is exactly the [private] of the other.

> Cheers,
> 
> Jacques Garrigue

Merci,
E.


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

* Re: [Caml-list] Private types
  2008-10-31  0:08     ` Jacques Garrigue
@ 2008-10-31 14:05       ` Dario Teixeira
  2008-11-01  9:52         ` Jacques Garrigue
  2008-11-01  1:52       ` Edgar Friendly
  1 sibling, 1 reply; 27+ messages in thread
From: Dario Teixeira @ 2008-10-31 14:05 UTC (permalink / raw)
  To: dra-news, Jacques Garrigue; +Cc: caml-list

Hi,

> Your intuition is correct that it would theoretically be possible to
> try subtyping in place of unification in some cases. The trouble is
> that thoses cases are not easy to specify (so that it would be hard
> for the programmer to known when he can remove a coercion), and that
> subtyping is potentially very costly (structural subtyping is much
> harder to check than the nominal subtyping you have in Java.)


Thanks for the explanation, Jacques.  If I understand correctly, by requiring
subtyping relations to be explicitly coerced, the "giant system of equations"
behind unification can be simplified because it doesn't need to worry about
all possible subtyping relations.  So in a sense this is also a matter of
computational tractability, right?

I have also been playing with 3.11's private types, and I would like to
share a problem I've come across.  Suppose I have a Foobar module defined
as follows (note the use of a type constraint):


module Foobar:
sig
	type foo_t = [ `A ]
	type bar_t = [ `B ]
	type foobar_t = [ foo_t | bar_t ]
	type 'a t = 'a constraint 'a = [< foobar_t ]

	val make_a: unit -> foo_t t
	val make_b: unit -> bar_t t
	val is_foo: [< foobar_t] t -> bool
	val is_bar: [< foobar_t] t -> bool
end =
struct
	type foo_t = [ `A ]
	type bar_t = [ `B ]
	type foobar_t = [ foo_t | bar_t ]
	type 'a t = 'a constraint 'a = [< foobar_t ]

	let make_a () = `A
	let make_b () = `B
	let is_foo = function `A -> true | `B -> false
	let is_bar = function `B -> true | `A -> false
end


Suppose also that I want to define a "is_foo" function in an external module.
This function only needs to pattern-match on Foobar.t values.  The following
code will work:

module Mymod:
sig
	open Foobar

	val is_foo2: [< foobar_t] t -> bool
end =
struct
	let is_foo2 = function `A -> true | `B -> false
end


But now consider that I want to enforce the creation of Foobar.t values only
via Foobar's constructor functions, but I would like to keep the possibility of
external modules to pattern-match on Foobar.t values.  In other words, change
Foobar but don't break Mymod.  The immediate (naïve) solution is to make
use of private types, thus changing the signature of Foobar to the following:


module Foobar:
sig
	type foo_t = [ `A ]
	type bar_t = [ `B ]
	type foobar_t = [ foo_t | bar_t ]
	type 'a t = private 'a constraint 'a = [< foobar_t ]

	val make_a: unit -> foo_t t
	val make_b: unit -> bar_t t
	val is_foo: [< foobar_t] t -> bool
	val is_bar: [< foobar_t] t -> bool
end = (...)


But this will break Mymod.  The compile will complain with the following error:

      Values do not match:
         val is_foo2 : [< `A | `B ] -> bool
       is not included in
         val is_foo2 : [< Foobar.foobar_t ] Foobar.t -> bool

Any ideas on how can I get around this problem?

Thanks!
Cheers,
Dario Teixeira






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

* Re: [Caml-list] Private types
  2008-10-30 21:54   ` David Allsopp
@ 2008-10-31  0:08     ` Jacques Garrigue
  2008-10-31 14:05       ` Dario Teixeira
  2008-11-01  1:52       ` Edgar Friendly
  0 siblings, 2 replies; 27+ messages in thread
From: Jacques Garrigue @ 2008-10-31  0:08 UTC (permalink / raw)
  To: dra-news; +Cc: caml-list

From: "David Allsopp" <dra-news@metastack.com>

> Thanks for this - although it's a link to an OCaml 3.10 manual so not
> applicable here it did point me to the correct chapter in the OCaml 3.11
> manual (I'd been looking in Part I of the manual and given up). What I
> should have written is
> 
> string_of_int (x :> int)
> 
> Though that does make me wonder why the coercion is mandatory. What happens
> if I *want* to allow the use of M.t values as though they were ints and only
> want to guarantee that they come from a specific sub-set of the integers
> (I'm thinking of database row IDs which is what I want to use them for)?
> Assuming that the type abbreviation doesn't contain type-variables, would
> there be anything theoretically preventing the inclusion of two keywords:
> 
> type t = private int      (* can be used as though it were an int  *)
> type t = very_private int (* requires a coercion to be used an int *)

Explicit coercions in ocaml are completely unrelated to casts in C or
Java, in that they only allow upcast (cast to a supertype). They are
also completely erasable: they do not produce any code after type
checking. So they are not there for any soundness reason, but just for
type inference purposes. There would be no point at all in having two
constructs: if the 1st one were possible, we wouldn't need the second.

As for type inference, (x :> int) is already an abbreviated form of
(x : t :> int), that only works if x is "known" to be of type t.
Since ocaml type inference does not include subtyping, there is no way
to do without coercions. To explain this, you should just see how the
type checker handles
     string_of_int x
It fetches the type of the string_of_int, int -> string, fetches the
type of x, which is t, and tries to unify int and t.
Since there is no direction in unification, this can only fail, as int
and t are not equivalent, just related through subtyping.

Your intuition is correct that it would theoretically be possible to
try subtyping in place of unification in some cases. The trouble is
that thoses cases are not easy to specify (so that it would be hard
for the programmer to known when he can remove a coercion), and that
subtyping is potentially very costly (structural subtyping is much
harder to check than the nominal subtyping you have in Java.)
So the current approach is to completely separate subtyping and type
inference, and require coercions everywhere subtyping is needed.

You can also compare that to the situation between int and float.
For most uses, int can be viewed as a subtype of float. However ocaml
separates the two, and requires coercion functions whenever you want
to use an int as a float.

Cheers,

Jacques Garrigue


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

* RE: [Caml-list] Private types
  2008-10-30 20:33 ` [Caml-list] " Daniel Bünzli
@ 2008-10-30 21:54   ` David Allsopp
  2008-10-31  0:08     ` Jacques Garrigue
  0 siblings, 1 reply; 27+ messages in thread
From: David Allsopp @ 2008-10-30 21:54 UTC (permalink / raw)
  To: 'Daniel Bünzli', 'OCaml List'

Daniel Bünzli wrote:
> Le 30 oct. 08 à 21:18, David Allsopp a écrit :
>
> > Shouldn't I now be able to say:
> >
> > string_of_int x;;
>
> I don't think so. According to the manual [1] the only thing you can  
> do on private types is pattern match or project their fields. I  
> doesn't mean your type can be substituted by int.

Strictly speaking the manual says that you can't construct values directly
(you can construct other values which contain private types, though, so it's
not limited to pattern matching or projection).

>
> [1] http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#htoc99

Thanks for this - although it's a link to an OCaml 3.10 manual so not
applicable here it did point me to the correct chapter in the OCaml 3.11
manual (I'd been looking in Part I of the manual and given up). What I
should have written is

string_of_int (x :> int)

Though that does make me wonder why the coercion is mandatory. What happens
if I *want* to allow the use of M.t values as though they were ints and only
want to guarantee that they come from a specific sub-set of the integers
(I'm thinking of database row IDs which is what I want to use them for)?
Assuming that the type abbreviation doesn't contain type-variables, would
there be anything theoretically preventing the inclusion of two keywords:

type t = private int      (* can be used as though it were an int  *)
type t = very_private int (* requires a coercion to be used an int *)

Or are there some very obvious programming gotchas that I'm missing if the
need to write the coercion were relaxed? The important point to me would
seem to be that if I say:

x + 1

then I get the *int* 1 and not the *M.t* value 1. As it stands, I can't see
a huge amount of difference, given that you have to write the coercion
everywhere, between a fully abstract type and a function M.getValue : t ->
int and a private int type.

(I'm assuming that if M.getValue is defined as %identity then the compiler
would optimise out the calls to it... of course if that isn't the case than
private ints are already one stage better!)

And one final thought - given that you can't assign to mutable members of
private record types, isn't a bit strange that you can change the contents
of private string values? Wouldn't having type t = private string where
character access is not possible give some people the immutable strings
they've been asking for in the past?


David


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

* Re: [Caml-list] Private types
  2008-10-30 20:18 Private types David Allsopp
  2008-10-30 20:33 ` [Caml-list] " Daniel Bünzli
@ 2008-10-30 21:47 ` Jérémie Dimino
  1 sibling, 0 replies; 27+ messages in thread
From: Jérémie Dimino @ 2008-10-30 21:47 UTC (permalink / raw)
  To: David Allsopp; +Cc: OCaml List

"David Allsopp" <dra-news@metastack.com> writes:

> I thought that the point of private types was that you could
> deconstruct them... so values of type M.t are valid wherever an int
> is used but not the converse.

It should probably be ok for immutable data but not for mutable
ones. One example is using String.set on a private string.

Jérémie


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

* Re: [Caml-list] Private types
  2008-10-30 20:18 Private types David Allsopp
@ 2008-10-30 20:33 ` Daniel Bünzli
  2008-10-30 21:54   ` David Allsopp
  2008-10-30 21:47 ` Jérémie Dimino
  1 sibling, 1 reply; 27+ messages in thread
From: Daniel Bünzli @ 2008-10-30 20:33 UTC (permalink / raw)
  To: OCaml List


Le 30 oct. 08 à 21:18, David Allsopp a écrit :

> Shouldn't I now be able to say:
>
> string_of_int x;;

I don't think so. According to the manual [1] the only thing you can  
do on private types is pattern match or project their fields. I  
doesn't mean your type can be substituted by int.

Daniel

[1] http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#htoc99


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

end of thread, other threads:[~2008-11-02 14:53 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-28 15:28 [Caml-list] Reading a large text file André Luiz Moura
2004-04-28 16:28 ` Richard Jones
2004-05-01 14:03 ` Brian Hurt
2004-05-01 15:43   ` Rahul Siddharthan
2004-05-01 16:00     ` [Caml-list] [OcamlDoc] langage support sejourne kevin
2004-05-14  7:15       ` Maxence Guesdon
2004-05-01 18:05     ` [Caml-list] Reading a large text file Richard Jones
2004-05-01 18:25       ` Charles Forsyth
2004-05-01 19:25       ` skaller
2004-05-01 19:51         ` Alain.Frisch
2004-05-01 20:40           ` skaller
2004-05-01 21:11             ` [Caml-list] Private types skaller
2004-05-01 21:33             ` [Caml-list] Reading a large text file Alain.Frisch
2004-05-17  5:28   ` Eric Stokes
2008-10-30 20:18 Private types David Allsopp
2008-10-30 20:33 ` [Caml-list] " Daniel Bünzli
2008-10-30 21:54   ` David Allsopp
2008-10-31  0:08     ` Jacques Garrigue
2008-10-31 14:05       ` Dario Teixeira
2008-11-01  9:52         ` Jacques Garrigue
2008-11-01  1:52       ` Edgar Friendly
2008-11-01  8:19         ` David Allsopp
2008-11-01 19:31           ` Edgar Friendly
2008-11-01 20:18             ` David Allsopp
2008-11-02 14:53               ` Edgar Friendly
2008-11-01 10:00         ` Jacques Garrigue
2008-11-01 19:41           ` Edgar Friendly
2008-10-30 21:47 ` Jérémie Dimino

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox