caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] two unrelated questions
@ 2001-04-25 21:08 Chris Hecker
  2001-04-26  0:38 ` Patrick M Doane
                   ` (3 more replies)
  0 siblings, 4 replies; 21+ messages in thread
From: Chris Hecker @ 2001-04-25 21:08 UTC (permalink / raw)
  To: caml-list


1.  What is the right "functional pattern" for early-outing on success
    while using an iter/map/fold type function?  Say I'm using iter to
    search for something in an opaque datastructure.  Should I throw
    an exception to get out, or is that bad style?  I guess this
    question only makes sense for iter, since map/fold produce results
    that you theoretically want to preserve.  So, the question is
    really, given an iter-style interface to a datastructure (one that
    takes an ('a -> unit)), how do you tell it to stop iterating?  I
    guess if the function was ('a -> bool) you could do it that way,
    but most iters aren't ((List|Array|Hashtbl).iter, for example).
    Is throwing an exception the best bet?

2.  I'm confused as to when the compiler decides to inline and when it
    doesn't.  None of the calls in the following program get inlined,
    regardless of the value of -inline in ocamlopt.  It seems so
    trivial, and in fact, I wrote it to show a friend how the compiler
    is really good (and after running dumpobj on the bytecode and
    looking at the asm from ocamlopt, we went and saw with dismay how
    Pervasives.fst and .snd are builtins and not inlined functions):

let a = 1,2

let myfst (a,b) = a
let mysnd (a,b) = b

let myfsti ((a,b):int*int) = a
let mysndi ((a,b):int*int) = b
    
let _ =
  myfst a + 1;
  1 + mysnd a;
  myfsti a;
  mysndi a

    
Chris


-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-25 21:08 [Caml-list] two unrelated questions Chris Hecker
@ 2001-04-26  0:38 ` Patrick M Doane
  2001-04-26  6:04   ` Judicaël Courant
  2001-04-26  8:22   ` Andreas Rossberg
  2001-04-26  1:13 ` Jacques Garrigue
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 21+ messages in thread
From: Patrick M Doane @ 2001-04-26  0:38 UTC (permalink / raw)
  To: Chris Hecker; +Cc: caml-list

On Wed, 25 Apr 2001, Chris Hecker wrote:

> 
> 1.  What is the right "functional pattern" for early-outing on success
>     while using an iter/map/fold type function?  Say I'm using iter to
>     search for something in an opaque datastructure.  Should I throw
>     an exception to get out, or is that bad style?  I guess this
>     question only makes sense for iter, since map/fold produce results
>     that you theoretically want to preserve.  So, the question is
>     really, given an iter-style interface to a datastructure (one that
>     takes an ('a -> unit)), how do you tell it to stop iterating?  I
>     guess if the function was ('a -> bool) you could do it that way,
>     but most iters aren't ((List|Array|Hashtbl).iter, for example).
>     Is throwing an exception the best bet?
> 

One way to think about exceptions is to treat them simply as control flow
expressions. For example, the 'break' statement is used in C/C++ to
early-out of iteration constructs. This translates naturally to
exceptions:

  exception Break
  try
    List.iter (fun ..  -> ...  raise Break) l
  with Break -> ()

We can even get labelled breaks like Java:

  exception Break of string
  try
    List.iter (fun ... ->
      try
        List.iter (fun ... ->
          if .. then raise (Break "inner")
                else raise (Break "outer")
        ) list1
      with Break "inner" -> ()
    ) list2
  with Break "outer" -> ()

I personally don't think this is bad style but others may have a different
opinion.

It also seems that the overhead for a try block in Caml is relatively low,
but I've never looked too much at the compiled code to see what it is
doing.

Patrick

-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-25 21:08 [Caml-list] two unrelated questions Chris Hecker
  2001-04-26  0:38 ` Patrick M Doane
@ 2001-04-26  1:13 ` Jacques Garrigue
  2001-04-26 13:47 ` Xavier Leroy
  2001-04-26 16:57 ` Mark Seaborn
  3 siblings, 0 replies; 21+ messages in thread
From: Jacques Garrigue @ 2001-04-26  1:13 UTC (permalink / raw)
  To: checker; +Cc: caml-list

From: Chris Hecker <checker@d6.com>

> 1.  What is the right "functional pattern" for early-outing on success
>     while using an iter/map/fold type function?  Say I'm using iter to
>     search for something in an opaque datastructure.  Should I throw
>     an exception to get out, or is that bad style?  I guess this
>     question only makes sense for iter, since map/fold produce results
>     that you theoretically want to preserve.  So, the question is
>     really, given an iter-style interface to a datastructure (one that
>     takes an ('a -> unit)), how do you tell it to stop iterating?  I
>     guess if the function was ('a -> bool) you could do it that way,
>     but most iters aren't ((List|Array|Hashtbl).iter, for example).
>     Is throwing an exception the best bet?

How to escape with an exception is described in section 8 of the
caml-light tutorial: http://caml.inria.fr/tutorial/index.html.
So I suppose this can be described as good style.
Particularly you can see in section 8.3 how to escape with a return
value, which is a natural thing to do in a search algorithm, and is a
bit nicer than using a reference cell.

Cheers,

Jacques Garrigue
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26  0:38 ` Patrick M Doane
@ 2001-04-26  6:04   ` Judicaël Courant
  2001-04-26 12:06     ` John Max Skaller
  2001-04-26  8:22   ` Andreas Rossberg
  1 sibling, 1 reply; 21+ messages in thread
From: Judicaël Courant @ 2001-04-26  6:04 UTC (permalink / raw)
  To: Patrick M Doane; +Cc: checker, caml-list

Hi,

On Wed, 25 Apr 2001 20:38:43 -0400 (EDT) Patrick M Doane wrote:
> 
> One way to think about exceptions is to treat them simply as control
flow
> expressions. For example, the 'break' statement is used in C/C++ to
> early-out of iteration constructs. This translates naturally to
> exceptions:
> 
>   exception Break
>   try
>     List.iter (fun ..  -> ...  raise Break) l
>   with Break -> ()
> 

Actually there is already such a predefined exception in the core library
of O'Caml. The doc says:

-------------------------------------------------------------------
exception Exit

     This exception is not raised by any library function. It is provided
for use in your programs. 
-------------------------------------------------------------------

Judicaël.
-- 
Judicael.Courant@lri.fr, http://www.lri.fr/~jcourant/
(+33) (0)1 69 15 64 85
"Montre moi des morceaux de ton monde, et je te montrerai le mien"
Tim, matricule #929, condamné à mort.
http://rozenn.picard.free.fr/tim.html

-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26  0:38 ` Patrick M Doane
  2001-04-26  6:04   ` Judicaël Courant
@ 2001-04-26  8:22   ` Andreas Rossberg
  1 sibling, 0 replies; 21+ messages in thread
From: Andreas Rossberg @ 2001-04-26  8:22 UTC (permalink / raw)
  To: caml-list; +Cc: Patrick M Doane

Patrick M Doane wrote:
> 
> We can even get labelled breaks like Java:
> 
>   exception Break of string
>   try
>     List.iter (fun ... ->
>       try
>         List.iter (fun ... ->
>           if .. then raise (Break "inner")
>                 else raise (Break "outer")
>         ) list1
>       with Break "inner" -> ()
>     ) list2
>   with Break "outer" -> ()

Is there any reason that declaring two different exceptions BreakInner
and BreakOuter does not suffice?

	- Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

"Computer games don't affect kids.
 If Pac Man affected us as kids, we would all be running around in
 darkened rooms, munching pills, and listening to repetitive music."
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26  6:04   ` Judicaël Courant
@ 2001-04-26 12:06     ` John Max Skaller
  2001-04-27  9:12       ` Anton Moscal
  2001-04-27 15:09       ` [Caml-list] " Brian Rogoff
  0 siblings, 2 replies; 21+ messages in thread
From: John Max Skaller @ 2001-04-26 12:06 UTC (permalink / raw)
  Cc: caml-list

"Judicaël Courant" wrote:

> >   exception Break
> >   try
> >     List.iter (fun ..  -> ...  raise Break) l
> >   with Break -> ()

Unfortunately:

	let f x = 
		exception Break 
		try ... raise Break ...
		with Break -> ()
	;;

is in error, because exception declarations must be at the top
level. This prevents desired localisation: this feature is not
as good as a labelled break for this purpose.

-- 
John (Max) Skaller, mailto:skaller@maxtal.com.au
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
checkout Vyper http://Vyper.sourceforge.net
download Interscript http://Interscript.sourceforge.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-25 21:08 [Caml-list] two unrelated questions Chris Hecker
  2001-04-26  0:38 ` Patrick M Doane
  2001-04-26  1:13 ` Jacques Garrigue
@ 2001-04-26 13:47 ` Xavier Leroy
  2001-04-26 22:34   ` Chris Hecker
  2001-04-26 16:57 ` Mark Seaborn
  3 siblings, 1 reply; 21+ messages in thread
From: Xavier Leroy @ 2001-04-26 13:47 UTC (permalink / raw)
  To: Chris Hecker; +Cc: caml-list

> 1.  What is the right "functional pattern" for early-outing on success
>     while using an iter/map/fold type function?
>     Is throwing an exception the best bet?

I believe so.

> 2.  I'm confused as to when the compiler decides to inline and when it
>     doesn't.  None of the calls in the following program get inlined,
>     regardless of the value of -inline in ocamlopt.

It's an embarrassing example of two distinct optimizations that
conflict, resulting in bad code :-)  

The first optimization is that constant data structures, such as the
tuple (1,2) in your example, are pre-built at compile-time rather than
dynamically built at run-time.  So, by the time we get to the inliner,
the "a" value is no longer syntactically a pair, but some sort of
special constant.

The second optimization is the tupled function optimization,
whereas functions taking a N-tuple of arguments are replaced by a
function taking N arguments.  Such functions are inlined only when
applied to an argument that is syntactically a N-tuple.  Otherwise,
the "slow path" (that takes a real tuple as argument, fetches
its N components, and jumps to the fast entry point) is followed, and
this turns inlining off.

You would get inlining in your example after rewriting it like this,
for instance:

> let myfst (a,b) = a
> let mysnd (a,b) = b
> 
> let myfsti ((a,b):int*int) = a
> let mysndi ((a,b):int*int) = b
>     
> let f x y =
>   myfst (x,y) + 1;
>   1 + mysnd (x,y);
>   myfsti (x,y);
>   mysndi (x,y)
>
> let _ = f 1 2

I agree this behavior is surprising and should be fixed at some point.

> (and after running dumpobj on the bytecode and
> looking at the asm from ocamlopt, we went and saw with dismay how
> Pervasives.fst and .snd are builtins and not inlined functions)

The bytecode compiler performs no inlining at all.  This is the main
reason why fst and snd are builtins (so that they do not generate
function calls in bytecoded programs).

- Xavier Leroy

-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-25 21:08 [Caml-list] two unrelated questions Chris Hecker
                   ` (2 preceding siblings ...)
  2001-04-26 13:47 ` Xavier Leroy
@ 2001-04-26 16:57 ` Mark Seaborn
  2001-04-26 22:20   ` John Max Skaller
  3 siblings, 1 reply; 21+ messages in thread
From: Mark Seaborn @ 2001-04-26 16:57 UTC (permalink / raw)
  To: caml-list

Chris Hecker <checker@d6.com> writes:

> 1.  What is the right "functional pattern" for early-outing on success
>     while using an iter/map/fold type function?  Say I'm using iter to
>     search for something in an opaque datastructure.  Should I throw
>     an exception to get out, or is that bad style?  I guess this
>     question only makes sense for iter, since map/fold produce results
>     that you theoretically want to preserve.  So, the question is
>     really, given an iter-style interface to a datastructure (one that
>     takes an ('a -> unit)), how do you tell it to stop iterating?  I
>     guess if the function was ('a -> bool) you could do it that way,
>     but most iters aren't ((List|Array|Hashtbl).iter, for example).
>     Is throwing an exception the best bet?

Wrapping up the exception-throwing method with a function that
provides an escaping continuation function is something you might
prefer stylistically.

Another way of doing it is to CPS-convert the fold function to get
something like:

let rec foldc kons knil l = match l with
  | [] -> knil
  | x::xs -> kons x knil (fun rest -> foldc kons rest xs)

Then `reverse' and `map' can be defined by:

let reverse l = foldc (fun x xs c -> c (x::xs)) [] l
let map f l = foldc (fun x xs c -> (f x)::(c xs)) [] l

(Notice that `foldc' can be used to traverse the list from
right-to-left as well as left-to-right by calling the continuation
function at a different time.)

A function to return the first value satisfying a predicate in a list
and break out of the fold operation can be defined by:

let first_such pred l =
  foldc (fun x _ c -> if pred x then Some x else c None)
    None l

This is more powerful than fold, but also harder to understand, and
easier to use wrongly if you forget to call the continuation function.

Also, if you re-order the arguments of foldc and pass it a return
continuation you get something you can use to thread multiple values
through (which is possibly more efficient in OCaml?), instead of just
using one collector value (and putting a tuple in it):

let rec foldc' kons l c knil = match l with
  | [] -> c knil
  | x::xs -> kons x (fun rest -> foldc' kons xs c rest) knil

for example:
  foldc' (fun x c l1 l2 -> c (x::l1) (x::l2))
    [1;2;3;4] (fun a b -> (a,b)) [] []
gives
  ([4;3;2;1], [4;3;2;1])

You can use this to stop a fold operation and restart it later, and
for building lazy lists out of any collection that provides a `foldc'
operation.  However, it starts to get difficult to understand the
order of evaluation, so I'm not sure whether this is very useful in
practice (it probably gets to the point where you may as well use a
lazy language instead) or whether it's just a handy way of obfuscating
your programs.

-- 
         Mark Seaborn
   - mseaborn@bigfoot.com - http://www.srcf.ucam.org/~mrs35/ -

          ``Anyone foolish enough to predict the outcome of
               this match is a fool'' -- Fred Trueman
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26 16:57 ` Mark Seaborn
@ 2001-04-26 22:20   ` John Max Skaller
  2001-05-01 21:08     ` Brian Rogoff
  0 siblings, 1 reply; 21+ messages in thread
From: John Max Skaller @ 2001-04-26 22:20 UTC (permalink / raw)
  To: Mark Seaborn; +Cc: caml-list

Mark Seaborn wrote:

> Another way of doing it is to CPS-convert the fold function to get
> something like:
> 
> let rec foldc kons knil l = match l with
>   | [] -> knil
>   | x::xs -> kons x knil (fun rest -> foldc kons rest xs)

> This is more powerful than fold, but also harder to understand,

	You're not kidding, on both counts :-)

	It's also 'ugly', because it only works for lists,
but this is only because you hard coded the destructor.
Passing it as an argument:

  let rec foldc remove kons knil l = match remove l with
	| (_,None) -> knil
	| (xs,Some x) -> kons x knil (fun rest -> foldc remove kons rest xs)

  let foldc_list = foldc (fun l -> match l with 
		| [] -> l,None
		| x::xs -> xs,Some x)

It's a pity there is no such destructor for a Hashtbl. 
[All C++ STL data structures have read iterators, which 
amount to destructors]

-- 
John (Max) Skaller, mailto:skaller@maxtal.com.au
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
checkout Vyper http://Vyper.sourceforge.net
download Interscript http://Interscript.sourceforge.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26 13:47 ` Xavier Leroy
@ 2001-04-26 22:34   ` Chris Hecker
  0 siblings, 0 replies; 21+ messages in thread
From: Chris Hecker @ 2001-04-26 22:34 UTC (permalink / raw)
  To: Xavier Leroy; +Cc: caml-list


>It's an embarrassing example of two distinct optimizations that
>conflict, resulting in bad code :-)  

Ah, thanks.  I have a strange talent for breaking things, I've found over the years.  The first thing I try never works.  I'd make a good tester.  :)

> The bytecode compiler performs no inlining at all.

Why is this?  I can think of a few reasonable arguments:

- if you want speed you'll compile to native
- bytecode is for size, and inlining hoses this
- you tested it on real-size apps and found cache coherency made non-inlines faster
- it's hard for some reason I don't understand
- haven't gotten around to it yet
- ???

Chris


-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26 12:06     ` John Max Skaller
@ 2001-04-27  9:12       ` Anton Moscal
  2001-04-29 22:24         ` Brian Rogoff
  2001-04-27 15:09       ` [Caml-list] " Brian Rogoff
  1 sibling, 1 reply; 21+ messages in thread
From: Anton Moscal @ 2001-04-27  9:12 UTC (permalink / raw)
  To: John Max Skaller; +Cc: caml-list

On Thu, 26 Apr 2001, John Max Skaller wrote:

> Unfortunately:
> 
> 	let f x = 
> 		exception Break 
> 		try ... raise Break ...
> 		with Break -> ()
> 	;;
> 
> is in error, because exception declarations must be at the top
> level. This prevents desired localisation: this feature is not
> as good as a labelled break for this purpose.

For this problem workaround exists:

let f x = 
   let module M = struct
        exception Break
        let v = try ... raise Break ... with Break ->...
       end
   in M.v

I made syntax extension for camlp4 and now can write something like this:

let f x = let exception Break in ...

Regards,
Anton
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26 12:06     ` John Max Skaller
  2001-04-27  9:12       ` Anton Moscal
@ 2001-04-27 15:09       ` Brian Rogoff
  2001-04-27 17:49         ` John Max Skaller
  1 sibling, 1 reply; 21+ messages in thread
From: Brian Rogoff @ 2001-04-27 15:09 UTC (permalink / raw)
  To: John Max Skaller; +Cc: caml-list

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: TEXT/PLAIN; charset=X-UNKNOWN, Size: 1002 bytes --]

On Thu, 26 Apr 2001, John Max Skaller wrote:
> "Judicaël Courant" wrote:
> 
> > >   exception Break
> > >   try
> > >     List.iter (fun ..  -> ...  raise Break) l
> > >   with Break -> ()
> 
> Unfortunately:
> 
> 	let f x = 
> 		exception Break 
> 		try ... raise Break ...
> 		with Break -> ()
> 	;;
> 
> is in error, because exception declarations must be at the top
> level. This prevents desired localisation: this feature is not
> as good as a labelled break for this purpose.

Well, this kind of thing is what local does in SML and a few people have
asked for it before. You can use the local module feature to do the
same thing.

let f x = 
  let module Local = struct 
    exception Break
    let f () = 
    try (print_endline ("hello " ^ x); raise Break) with Break -> ()
  end in
  Local.f ()

This is a very handy feature of OCaml. 

-- Brian



-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-27 15:09       ` [Caml-list] " Brian Rogoff
@ 2001-04-27 17:49         ` John Max Skaller
  0 siblings, 0 replies; 21+ messages in thread
From: John Max Skaller @ 2001-04-27 17:49 UTC (permalink / raw)
  To: Brian Rogoff; +Cc: caml-list

Brian Rogoff wrote:
> On Thu, 26 Apr 2001, John Max Skaller wrote:
> > Unfortunately:
> >
> >       let f x =
> >               exception Break
> >               try ... raise Break ...
> >               with Break -> ()
> >       ;;
> >
> > is in error, because exception declarations must be at the top
> > level. 

> Well, this kind of thing is what local does in SML and a few people have
> asked for it before. You can use the local module feature to do the
> same thing.
> 
> let f x =
>   let module Local = struct
>     exception Break
>     let f () =
>     try (print_endline ("hello " ^ x); raise Break) with Break -> ()
>   end in
>   Local.f ()

	Actually, this works too:

	let f x = 
		let module Local = struct exception Break end in
		try raise Local.Break with Local.Break -> ()

Furthermore, this doesn't work:

	let f x = 
		type integer = int
		let i:integer = 1 in ...

but this does:

	let f x = 
		let module Local = struct type integer = int end in
		let i: Local.integer = 1 in ...
		

which makes me wonder why it is necessary to wrap exception 
declarations and type aliases in modules: is there a semantic
reason I'm missing, or is it just a parsing issue?

-- 
John (Max) Skaller, mailto:skaller@maxtal.com.au
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
checkout Vyper http://Vyper.sourceforge.net
download Interscript http://Interscript.sourceforge.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-27  9:12       ` Anton Moscal
@ 2001-04-29 22:24         ` Brian Rogoff
  2001-04-30 18:57           ` Fergus Henderson
  2001-05-01  1:31           ` Jacques Garrigue
  0 siblings, 2 replies; 21+ messages in thread
From: Brian Rogoff @ 2001-04-29 22:24 UTC (permalink / raw)
  To: Anton Moscal; +Cc: John Max Skaller, caml-list

On Fri, 27 Apr 2001, Anton Moscal wrote:
> For this problem workaround exists:
> 
> let f x = 
>    let module M = struct
>         exception Break
>         let v = try ... raise Break ... with Break ->...
>        end
>    in M.v

I think the real beauty of this local module feature is that it allows
things like  a local open, which may make open more palatable to
open-phobes. For instance if you want to get a date but don't want to
"pollute" the namespace with an open'ed Unix module you can write 

let get_date () =
  let module M = struct
      open Unix
      let current_time = localtime (time())
      let current_date =
        { year   = current_time.tm_year
        ; month  = current_time.tm_mon + 1
        ; day    = current_time.tm_mday
        ; hour   = current_time.tm_hour
        ; minute = current_time.tm_min
        ; second = current_time.tm_sec
        }
    end
  in M.current_date

though I take it that these kinds of tricks weren't the original goal of
the feature. Still, the syntax is light so these are very painless
workarounds even without the P4 prettification. 

-- Brian


-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-29 22:24         ` Brian Rogoff
@ 2001-04-30 18:57           ` Fergus Henderson
  2001-05-01  1:31           ` Jacques Garrigue
  1 sibling, 0 replies; 21+ messages in thread
From: Fergus Henderson @ 2001-04-30 18:57 UTC (permalink / raw)
  To: Brian Rogoff; +Cc: Anton Moscal, John Max Skaller, caml-list

[This is getting a bit off-topic, sorry]

On 29-Apr-2001, Brian Rogoff <bpr@best.com> wrote:
> For instance if you want to get a date but don't want to
> "pollute" the namespace with an open'ed Unix module you can write 
> 
> let get_date () =
>   let module M = struct
>       open Unix
>       let current_time = localtime (time())
>       let current_date =
>         { year   = current_time.tm_year
>         ; month  = current_time.tm_mon + 1
>         ; day    = current_time.tm_mday
>         ; hour   = current_time.tm_hour
>         ; minute = current_time.tm_min
>         ; second = current_time.tm_sec
>         }
>     end
>   in M.current_date

If you're going to adjust the month, then you should
adjust the year too:

	{ year   = current_time.tm_year + 1900

Otherwise the results will match neither human usage, nor Posix.

-- 
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-29 22:24         ` Brian Rogoff
  2001-04-30 18:57           ` Fergus Henderson
@ 2001-05-01  1:31           ` Jacques Garrigue
  2001-05-01 12:45             ` [Caml-list] " Ken Friis Larsen
  1 sibling, 1 reply; 21+ messages in thread
From: Jacques Garrigue @ 2001-05-01  1:31 UTC (permalink / raw)
  To: bpr; +Cc: caml-list

From: Brian Rogoff <bpr@best.com>

> I think the real beauty of this local module feature is that it allows
> things like  a local open, which may make open more palatable to
> open-phobes.
> 
> though I take it that these kinds of tricks weren't the original goal of
> the feature. Still, the syntax is light so these are very painless
> workarounds even without the P4 prettification. 

Indeed, I think they were not the original goal.
As I heard it from Xavier, this was mostly intended to allow local
instances of functors.

Particularly, local exception definitions are one of the rare features
present in SML and absent in Caml, and that some SML developpers think
that Caml is right about :-)
That is, defining local exceptions (and local types also) is a very
fine way to shoot oneself in the foot. You end up having plenty of
exceptions (or types) with the same name (impossible to distinguish at
toplevel), but incompatible. For types, this is still ok since the
type checker does not allow it to escape its scope; which can give you
funny errors:

  # let module M = struct type t = A | B end in M.A;;
  This `let module' expression has type M.t
  In this type, the locally bound module name M escapes its scope

For exceptions, logically a locally defined exception escaping its
scope should be a fatal error, but this is not the case (cannot be
really enforced). So you can end up at toplevel getting an exception
of an unknown name, impossible to catch. (This is the problem SMLers
cite most often).

On the other hand, I perfectly agree with you that opening a module
locally is something you want to do often, and causes no safety
problem at all.
That's one of the reasons I think mixing it with let module is not
good: the let module feature is theoretically subtle, and should be
used with care, while a let open construct does nothing (just changes
the static scope), and does not require the same caution.

Cheers,

Jacques Garrigue
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* [Caml-list] Re: two unrelated questions
  2001-05-01  1:31           ` Jacques Garrigue
@ 2001-05-01 12:45             ` Ken Friis Larsen
  0 siblings, 0 replies; 21+ messages in thread
From: Ken Friis Larsen @ 2001-05-01 12:45 UTC (permalink / raw)
  To: caml-list

"Jacques" == Jacques Garrigue <garrigue@kurims.kyoto-u.ac.jp> writes:

 Jacques>  Particularly, local exception definitions are one of the
 Jacques>  rare features present in SML and absent in Caml, and that
 Jacques>  some SML developpers think that Caml is right about :-)

But some of us really like that feature because it allows an elegant
*user* implementation of dynamic typing.


The task is to implement a structure with the signature DYN:

module type DYN = 
  sig 
    type dyn 
    val wrap: unit -> ('a -> dyn) * (dyn -> 'a)
  end


The cannonical SML solution is to use exceptions for this.  Here is a
Caml version of that solution:

module Dyn1 : DYN =
  struct 
    type dyn = exn
    let wrap () =
      let module D = struct exception DYN of 'a end in  
      (function x -> D.DYN x), 
      (function D.DYN x -> x)      
  end 
    
(But I'm unfortunately not strong enough in O'Caml because this gives
the error "Unbound type parameter 'a".  How do I fix that?  Note that
the implementation works as expected if we make 'a a fixed type.)

You can argue that you don't need that feature of exceptions just to
implement dynamic typing, because DYN can be implemented using
closures and references:

module Dyn2 : DYN = 
  struct
    type dyn = unit -> unit
    let wrap () =
      let r = ref None in
      (fun x -> fun () -> r := Some x),
      (fun f -> ( r := None
                ; f()
                ; match !r with
                    Some x -> x
                  | None   -> raise (Failure"Using the wrong unwrapper")
                ))     
  end


Cheers,

--Ken
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-04-26 22:20   ` John Max Skaller
@ 2001-05-01 21:08     ` Brian Rogoff
  2001-05-01 23:30       ` John Max Skaller
  2001-05-02  0:03       ` John Max Skaller
  0 siblings, 2 replies; 21+ messages in thread
From: Brian Rogoff @ 2001-05-01 21:08 UTC (permalink / raw)
  To: John Max Skaller; +Cc: Mark Seaborn, caml-list

On Fri, 27 Apr 2001, John Max Skaller wrote:
> Mark Seaborn wrote:
> > Another way of doing it is to CPS-convert the fold function to get
> > something like:
> > 
> > let rec foldc kons knil l = match l with
> >   | [] -> knil
> >   | x::xs -> kons x knil (fun rest -> foldc kons rest xs)
> 
> > This is more powerful than fold, but also harder to understand,
> 
> 	You're not kidding, on both counts :-)

I admit, I'm a sucker for CPS tricks. They are kind of hard to follow
sometimes, even for the initiated. 

> 	It's also 'ugly', because it only works for lists,
> but this is only because you hard coded the destructor.
> Passing it as an argument:
> 
>   let rec foldc remove kons knil l = match remove l with
> 	| (_,None) -> knil
> 	| (xs,Some x) -> kons x knil (fun rest -> foldc remove kons rest xs)
> 
>   let foldc_list = foldc (fun l -> match l with 
> 		| [] -> l,None
> 		| x::xs -> xs,Some x)

Yes, this is better. You can also use it with the inductive graph types 
defined by Martin Erwig. He names his destructor "match" (I rename it 
"extract" in my version of his library) and his constructor embed; the 
destructor takes a graph to a "context" (a node with incoming and outgoing
edges) and a graph with that context removed. 

It also fits on to OCaml Sets nicely too. Of course, you should always
remember that the value restriction sucks and that eta expansion is your
friend, and write it like this ;-)

let set_destruct s = 
  if is_empty s then (s, None) 
  else 
    let elt = PolySet.choose s in 
    let s'  = PolySet.remove elt s in 
    (s', Some elt) (* another case for left to right :-) *)

let foldc_set kons knil l = foldc set_destruct kons knil l 

> It's a pity there is no such destructor for a Hashtbl. 
> [All C++ STL data structures have read iterators, which 
> amount to destructors]

Are they really the same? I think of STL style iterators as being more 
similar to array indices, and arrays (and hashtables) are not defined
inductively like lists, trees, and graphs, etc. 

As I'm sure you know, there is an easy enough transformation from
hashtables (and arrays) to lists, like the following 

let pairs_of_hashtbl ht = 
  let pl_ref = ref [] in 
  let fn a b = (pl_ref := (a,b)::(!pl_ref) in 
  (Hashtbl.iter fn ht; !pl_ref)

which gives you a simple adaptor for folds. I think it's a pity from this 
POV that Map doesn't have an "is_empty" predicate and a "choose" which 
allow you to hand code a destructor analogous to your list destructor and
the set destructor above. 

-- Brian


-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-05-01 21:08     ` Brian Rogoff
@ 2001-05-01 23:30       ` John Max Skaller
  2001-05-02  0:03       ` John Max Skaller
  1 sibling, 0 replies; 21+ messages in thread
From: John Max Skaller @ 2001-05-01 23:30 UTC (permalink / raw)
  To: Brian Rogoff; +Cc: Mark Seaborn, caml-list

Brian Rogoff wrote:
> 
I wrote:

> >   let rec foldc remove kons knil l = match remove l with
> >       | (_,None) -> knil
> >       | (xs,Some x) -> kons x knil (fun rest -> foldc remove kons rest xs)
> >
> >   let foldc_list = foldc (fun l -> match l with
> >               | [] -> l,None
> >               | x::xs -> xs,Some x)

	But this doesn't actually work: it makes the types monomorphic unknowns
('_a etc). I should have written out the parameters explicitly to avoid
this:

	let foldc_list kons knil l = ....
 
-- 
John (Max) Skaller, mailto:skaller@maxtal.com.au
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
checkout Vyper http://Vyper.sourceforge.net
download Interscript http://Interscript.sourceforge.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* Re: [Caml-list] two unrelated questions
  2001-05-01 21:08     ` Brian Rogoff
  2001-05-01 23:30       ` John Max Skaller
@ 2001-05-02  0:03       ` John Max Skaller
  1 sibling, 0 replies; 21+ messages in thread
From: John Max Skaller @ 2001-05-02  0:03 UTC (permalink / raw)
  To: Brian Rogoff; +Cc: Mark Seaborn, caml-list

Brian Rogoff wrote:

> > It's a pity there is no such destructor for a Hashtbl.
> > [All C++ STL data structures have read iterators, which
> > amount to destructors]
> 
> Are they really the same? I think of STL style iterators as being more
> similar to array indices, and arrays (and hashtables) are not defined
> inductively like lists, trees, and graphs, etc.

	Well, for an iterator p, there are three operations:

	*p
	p++
	p==q

But they're usually combined like:

	*p++

which is equivalent to getting one element of the container p denotes,
and adjusting p to denote the rest of the container.

> As I'm sure you know, there is an easy enough transformation from
> hashtables (and arrays) to lists, like the following
> 
> let pairs_of_hashtbl ht =
>   let pl_ref = ref [] in
>   let fn a b = (pl_ref := (a,b)::(!pl_ref) in
>   (Hashtbl.iter fn ht; !pl_ref)

	Sure, but this requires building a new data structure.
Even if that is OK for traversal, it can't handle mutating
operations.

	Of course, people don't use STL algorithms as much in C++
as they might, because there is no support for nested anonymous
functions (lambdas) or currying, which are essential for localisation.
And of course Ocaml is _good_ at that :-)

-- 
John (Max) Skaller, mailto:skaller@maxtal.com.au
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
checkout Vyper http://Vyper.sourceforge.net
download Interscript http://Interscript.sourceforge.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

* RE: [Caml-list] two unrelated questions
@ 2001-05-01 17:25 Dave Berry
  0 siblings, 0 replies; 21+ messages in thread
From: Dave Berry @ 2001-05-01 17:25 UTC (permalink / raw)
  To: Jacques Garrigue, bpr; +Cc: caml-list

Even a top level exception can escape its scope, e.g. if a signature doesn't
include an exception raised by one of the functions in the signature.  The
problem I (as an SMLer) cite most often is exceptions - not just local
exceptions - escaping their scope.

Having said that, I think it best to have two distinct features: exceptions
and breaks.  Exceptions are top-level, monomorphic, and comparatively easy
to track.  Breaks are declared in function bodies, potentially polymorphic,
and should be banned from exiting the scope of their declaration.  This
would entail limits on how breaks could be used, to make the flow control
tractable.  I don't know whether there is a suitable flow control algorithm
that would give reasonable flexibility while still ensuring this safety
requirement.


-----Original Message-----
From: Jacques Garrigue [mailto:garrigue@kurims.kyoto-u.ac.jp]
Sent: Tuesday, May 01, 2001 2:31
To: bpr@best.com
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] two unrelated questions

That is, defining local exceptions (and local types also) is a very
fine way to shoot oneself in the foot. You end up having plenty of
exceptions (or types) with the same name (impossible to distinguish at
toplevel), but incompatible. 

For exceptions, logically a locally defined exception escaping its
scope should be a fatal error, but this is not the case (cannot be
really enforced). So you can end up at toplevel getting an exception
of an unknown name, impossible to catch. (This is the problem SMLers
cite most often).

-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr


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

end of thread, other threads:[~2001-05-02 11:21 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-04-25 21:08 [Caml-list] two unrelated questions Chris Hecker
2001-04-26  0:38 ` Patrick M Doane
2001-04-26  6:04   ` Judicaël Courant
2001-04-26 12:06     ` John Max Skaller
2001-04-27  9:12       ` Anton Moscal
2001-04-29 22:24         ` Brian Rogoff
2001-04-30 18:57           ` Fergus Henderson
2001-05-01  1:31           ` Jacques Garrigue
2001-05-01 12:45             ` [Caml-list] " Ken Friis Larsen
2001-04-27 15:09       ` [Caml-list] " Brian Rogoff
2001-04-27 17:49         ` John Max Skaller
2001-04-26  8:22   ` Andreas Rossberg
2001-04-26  1:13 ` Jacques Garrigue
2001-04-26 13:47 ` Xavier Leroy
2001-04-26 22:34   ` Chris Hecker
2001-04-26 16:57 ` Mark Seaborn
2001-04-26 22:20   ` John Max Skaller
2001-05-01 21:08     ` Brian Rogoff
2001-05-01 23:30       ` John Max Skaller
2001-05-02  0:03       ` John Max Skaller
2001-05-01 17:25 Dave Berry

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