From: oleg@pobox.com
To: kirillkh@gmail.com
Cc: caml-list@inria.fr
Subject: Locally-polymorphic exceptions [was: folding over a file]
Date: Wed, 3 Oct 2007 01:35:29 -0700 (PDT) [thread overview]
Message-ID: <20071003083529.40DA2A99F@Adric.metnet.fnmoc.navy.mil> (raw)
kirillkh wrote
> Is there a way to instantiate an exception with a value of unspecified type
> and then do explicit casting on catch?
Surprisingly, the answer in many (or all?) cases is yes. The answer is
definitely yes in the case when we need to define an exception local
to a polymorphic function. Incidentally, SML permits declarations of
such local exceptions whose type is tied to that of the host
polymorphic function. That feature has been used to implement
delimited continuations. Perhaps unsurprisingly, delimited
continuations can be used to implement such locally-polymorphic
exceptions.
The recent thread gave a good motivation for locally polymorphic
exceptions: writing a library function fold_file. The following code
has been proposed.
> exception Done of 'a
>
> let fold_file (file: in_channel)
> (read_func: in_channel->'a)
> (elem_func: 'a->'b->'b)
> (seed: 'b) =
> let rec loop prev_val =
> let input =
> try read_func file
> with End_of_file -> raise (Done prev_val)
> in
> let combined_val = elem_func input prev_val in
> loop combined_val
> in
> try loop seed with Done x -> x
Alas, the compiler does not accept the exception declaration, because
the declaration says that the exception should carry a value of all
types. There is no value that belongs to all types (and if it were, it
wouldn't be useful). But we don't actually need the value of all
types. We need the value of our Done exception to have the same type
as the result of the polymorphic function fold_file. We should have
declared the exception Done _inside_ fold_file. And that can be done:
Delimcc.prompt is precisely this type of `local exceptions'.
So, we can implement fold_file, by slightly adjusting the above code:
let fold_file (file: in_channel)
(read_func: in_channel->'a)
(elem_func: 'a->'b->'b)
(seed: 'b) =
let result = new_prompt () in (* here is our local exn declaration *)
let rec loop prev_val =
let input =
try read_func file
with End_of_file -> abort result prev_val
in
let combined_val = elem_func input prev_val in
loop combined_val
in
push_prompt result (fun () -> loop seed)
;;
(*
val fold_file :
in_channel -> (in_channel -> 'a) -> ('a -> 'b -> 'b) -> 'b -> 'b = <fun>
*)
let line_count filename =
let f = open_in filename in
let counter _ count = count + 1 in
fold_file f input_line counter 0;;
(*
val line_count : string -> int = <fun>
*)
let test = line_count "/etc/motd";;
(*
val test : int = 24
*)
The analogy between exceptions and delimited continuations is
profound: in fact, delimited continuations are implemented in terms of
exceptions. Abort is truly raise. Well, observationally. The current
delimcc library tried to follow Dybvig, Sabry and Peyton-Jones
interface -- which, being minimalistic, did not include abort as a
primitive. We have to implement abort in terms of take_subcont, which
is wasteful as we save the captured continuation for no good
reason. Internally, the library does have an abort primitive, and it
indeed works in the same way as raise.
next reply other threads:[~2007-10-03 8:37 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-03 8:35 oleg [this message]
2007-10-03 11:27 ` kirillkh
2007-10-03 11:48 ` [Caml-list] " Daniel de Rauglaudre
2007-10-03 12:19 ` kirillkh
2007-10-03 12:32 ` Daniel de Rauglaudre
2007-10-03 14:34 ` kirillkh
2007-10-03 20:39 ` Christophe Raffalli
2007-10-03 22:50 ` Unsoundness is essential skaller
2007-10-03 23:13 ` [Caml-list] " Jacques Carette
2007-10-04 1:24 ` skaller
2007-10-04 11:26 ` David Allsopp
2007-10-04 12:45 ` Vincent Hanquez
2007-10-04 15:07 ` skaller
2007-10-03 23:13 ` Vincent Aravantinos
2007-10-04 1:49 ` skaller
2007-10-03 23:28 ` Joshua D. Guttman
2007-10-04 1:52 ` skaller
2007-10-04 2:35 ` Brian Hurt
2007-10-04 7:46 ` Christophe Raffalli
2007-10-04 8:56 ` Arnaud Spiwack
2007-10-04 14:49 ` skaller
2007-10-04 15:00 ` Harrison, John R
2007-10-04 15:29 ` Andrej Bauer
2007-10-04 16:25 ` skaller
2007-10-04 18:17 ` Arnaud Spiwack
2007-10-04 20:54 ` skaller
2007-10-04 22:24 ` Arnaud Spiwack
2007-10-04 16:37 ` skaller
2007-10-04 18:59 ` Christophe Raffalli
2007-10-04 15:04 ` Andrej Bauer
2007-10-04 15:57 ` Christophe Raffalli
2007-10-04 16:03 ` skaller
2007-10-04 20:02 ` Ken Rose
2007-10-04 21:00 ` skaller
2007-10-04 15:31 ` Lukasz Stafiniak
2007-10-04 17:56 ` rossberg
2007-10-04 19:56 ` skaller
2007-10-04 21:07 ` rossberg
2007-10-04 22:23 ` skaller
2007-10-05 2:48 ` Bárður Árantsson
2007-10-04 2:16 ` Locally-polymorphic exceptions [was: folding over a file] oleg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071003083529.40DA2A99F@Adric.metnet.fnmoc.navy.mil \
--to=oleg@pobox.com \
--cc=caml-list@inria.fr \
--cc=kirillkh@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).