* Locally-polymorphic exceptions [was: folding over a file] @ 2007-10-03 8:35 oleg 2007-10-03 11:27 ` kirillkh 0 siblings, 1 reply; 41+ messages in thread From: oleg @ 2007-10-03 8:35 UTC (permalink / raw) To: kirillkh; +Cc: caml-list 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. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 8:35 Locally-polymorphic exceptions [was: folding over a file] oleg @ 2007-10-03 11:27 ` kirillkh 2007-10-03 11:48 ` [Caml-list] " Daniel de Rauglaudre ` (2 more replies) 0 siblings, 3 replies; 41+ messages in thread From: kirillkh @ 2007-10-03 11:27 UTC (permalink / raw) To: oleg; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 4039 bytes --] Hi Oleg, This looks excellent! I am especially delighted with the fact you don't have to declare this single-use exception in the global scope anymore. Could you be more specific regarding the continuations' performance impact? Would it matter in practice? Would you recommend using this function in a general-purpose library instead of the imperative-style implementation that was suggested? Also, is there a good manual on delimited continuations for a beginner with minimum of external references? I have tried to read your papers, but it's hard to advance because some of the complex stuff is explained elsewhere. -Kirill 2007/10/3, oleg@pobox.com <oleg@pobox.com>: > > > 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. > > [-- Attachment #2: Type: text/html, Size: 5551 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 11:27 ` kirillkh @ 2007-10-03 11:48 ` Daniel de Rauglaudre 2007-10-03 12:19 ` kirillkh 2007-10-03 20:39 ` Christophe Raffalli 2007-10-04 2:16 ` Locally-polymorphic exceptions [was: folding over a file] oleg 2 siblings, 1 reply; 41+ messages in thread From: Daniel de Rauglaudre @ 2007-10-03 11:48 UTC (permalink / raw) To: caml-list Hi, > 2007/10/3, oleg@pobox.com <oleg@pobox.com>: > > exception Done of 'a > > let fold_file (file: in_channel) > (read_func: in_channel->'a) > (elem_func: 'a->'b->'b) > (seed: 'b) = > [...] Personnally, I don't like exceptions because they generally control too much part of code. I often practice things like: match try Some (...) with [ Exception -> None ] with [ Some v -> blabla | None -> blublu ] I would write your function like this: value fold_file (file : in_channel) (read_func : in_channel -> 'a) (elem_func : 'a -> 'b -> 'b) (seed : 'b) = let rec loop prev_val = match try Some (read_func file) with [ End_of_file -> None ] with [ Some input -> let combined_val = elem_func input prev_val in loop combined_val | None -> prev_val ] in loop seed ; -- Daniel de Rauglaudre http://pauillac.inria.fr/~ddr/ ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 11:48 ` [Caml-list] " Daniel de Rauglaudre @ 2007-10-03 12:19 ` kirillkh 2007-10-03 12:32 ` Daniel de Rauglaudre 0 siblings, 1 reply; 41+ messages in thread From: kirillkh @ 2007-10-03 12:19 UTC (permalink / raw) To: Daniel de Rauglaudre; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 1748 bytes --] Hi, 2007/10/3, Daniel de Rauglaudre <daniel.de_rauglaudre@inria.fr>: > > Hi, > > > 2007/10/3, oleg@pobox.com <oleg@pobox.com>: > > > > exception Done of 'a > > > > let fold_file (file: in_channel) > > (read_func: in_channel->'a) > > (elem_func: 'a->'b->'b) > > (seed: 'b) = > > [...] > > Personnally, I don't like exceptions because they generally control too > much part of code. It's easy enough to localize the exception scope in this case and to see that catching it at the top recursive invocation gets rid of it for sure. Even the most dreadful beast is harmless, when encapsulated in a cage. (C) I wonder what are continuations' maintenance properties, though. Any comments? I'm not fluent in them, yet. I often practice things like: > > match try Some (...) with [ Exception -> None ] with > [ Some v -> blabla > | None -> blublu ] > > I would write your function like this: > > value fold_file (file : in_channel) (read_func : in_channel -> 'a) > (elem_func : 'a -> 'b -> 'b) (seed : 'b) > = > let rec loop prev_val = > match try Some (read_func file) with [ End_of_file -> None ] with > [ Some input -> > let combined_val = elem_func input prev_val in > loop combined_val > | None -> prev_val ] > in > loop seed > ; A similar solution has been proposed in the original discussion ("best and fastest way to read lines from a file?" thread). But then someone suggested using a second exception instead, which is better performance-wise, since it avoids variant allocations on the common code path. What I tried to do with polymorphic exception is implement a generalized channel fold combinator based on this idea. -Kirill [-- Attachment #2: Type: text/html, Size: 2991 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 12:19 ` kirillkh @ 2007-10-03 12:32 ` Daniel de Rauglaudre 2007-10-03 14:34 ` kirillkh 0 siblings, 1 reply; 41+ messages in thread From: Daniel de Rauglaudre @ 2007-10-03 12:32 UTC (permalink / raw) To: caml-list Hi, On Wed, Oct 03, 2007 at 02:19:56PM +0200, kirillkh wrote: > But then someone suggested using a second exception instead, which > is better performance-wise [...] Is that been checked ? And the two implementations tested ? What are the results, in time ? -- Daniel de Rauglaudre http://pauillac.inria.fr/~ddr/ ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 12:32 ` Daniel de Rauglaudre @ 2007-10-03 14:34 ` kirillkh 0 siblings, 0 replies; 41+ messages in thread From: kirillkh @ 2007-10-03 14:34 UTC (permalink / raw) To: Daniel de Rauglaudre; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 1676 bytes --] 2007/10/3, Daniel de Rauglaudre <daniel.de_rauglaudre@inria.fr>: > > Hi, > > On Wed, Oct 03, 2007 at 02:19:56PM +0200, kirillkh wrote: > > > But then someone suggested using a second exception instead, which > > is better performance-wise [...] > > Is that been checked ? And the two implementations tested ? What are the > results, in time ? > Tested from the top-level on a text file with 11mln lines: variants: 8.081 8.021 8.072 8.052 8.011 => avg=8.0474 exceptions: 7.801 7.902 7.822 7.901 7.832 => avg=7.8512 ----------------------------- total: exceptions are 2.44% faster I'm having troubles with ocamlopt (windows machine), can anyone do a similar test with it? Here's the code used (it's the pre-combinator version of line counter): exceptions (lcex.ml): exception Done of int;; let line_count filename = let file = open_in filename in let rec loop count = let _ = try input_line file with End_of_file -> raise (Done count) in loop (count + 1) in try loop 0 with Done x -> x ;; let start_time = Sys.time() in let count = line_count "c:/kirill/ocaml/test3.txt" in let diff = Sys.time() -. start_time in Printf.printf "count: %d, time: %f" count diff;; variants(lcvar.ml): let readline f = try Some (input_line f) with End_of_file -> None;; let line_count filename = let f = open_in filename in let rec loop count = match (readline f) with | Some(_) -> loop (count+1) | None -> count in loop 0;; let start_time = Sys.time() in let count = line_count "c:/kirill/ocaml/test3.txt" in let diff = Sys.time() -. start_time in Printf.printf "count: %d, time: %f" count diff;; -Kirill [-- Attachment #2: Type: text/html, Size: 2679 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 11:27 ` kirillkh 2007-10-03 11:48 ` [Caml-list] " Daniel de Rauglaudre @ 2007-10-03 20:39 ` Christophe Raffalli 2007-10-03 22:50 ` Unsoundness is essential skaller 2007-10-04 2:16 ` Locally-polymorphic exceptions [was: folding over a file] oleg 2 siblings, 1 reply; 41+ messages in thread From: Christophe Raffalli @ 2007-10-03 20:39 UTC (permalink / raw) To: kirillkh; +Cc: oleg, caml-list [-- Attachment #1.1: Type: text/plain, Size: 2746 bytes --] Hi, > > > 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 > In fact, if elem_func is known by the type checker not to raise any exception, then the exception need not to be garded by the Done constructor and the following program is safe: > 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 prev_val > in > let combined_val = elem_func input prev_val in > loop combined_val > in > try loop seed with x -> x The only problem is that current type-checker do not treat exception well and reject this kind of code .... Just for fun (I could not resist), here is the pml code which is accepeted, but is useless since pml can not read file yet ;-) ---------- pml code --------- (* f,a,b are declared type variables, a => b is the type of a function that raises no exception a -> b | e is the type of a function that raises only exception of type e a -> b is the type of a function with no indication about exceptions *) val (f,a,b) fold_file:(f => (f -> a | [EOF[]]) => (a=>b=>b) => b => b) file read_func elem_func seed = let rec loop prev_val = let input = try read_func file with EOF[] -> raise prev_val in let combined_val = elem_func input prev_val in loop combined_val in try loop seed with x -> x ------------------------------- So the story is by saying (wrongly) that it is too heavy to anottate arrow types with exceptions, making the arrow type a ternary type construct, ML is missing a lot ... -- Christophe Raffalli Universite de Savoie Batiment Le Chablais, bureau 21 73376 Le Bourget-du-Lac Cedex tel: (33) 4 79 75 81 03 fax: (33) 4 79 75 87 42 mail: Christophe.Raffalli@univ-savoie.fr www: http://www.lama.univ-savoie.fr/~RAFFALLI --------------------------------------------- IMPORTANT: this mail is signed using PGP/MIME At least Enigmail/Mozilla, mutt or evolution can check this signature. The public key is stored on www.keyserver.net --------------------------------------------- [-- Attachment #1.2: Christophe.Raffalli.vcf --] [-- Type: text/x-vcard, Size: 310 bytes --] begin:vcard fn:Christophe Raffalli n:Raffalli;Christophe org:LAMA (UMR 5127) email;internet:christophe.raffalli@univ-savoie.fr title;quoted-printable:Ma=C3=AEtre de conf=C3=A9rences tel;work:+33 4 79 75 81 03 note:http://www.lama.univ-savoie.fr/~raffalli x-mozilla-html:TRUE version:2.1 end:vcard [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 249 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Unsoundness is essential 2007-10-03 20:39 ` Christophe Raffalli @ 2007-10-03 22:50 ` skaller 2007-10-03 23:13 ` [Caml-list] " Jacques Carette ` (4 more replies) 0 siblings, 5 replies; 41+ messages in thread From: skaller @ 2007-10-03 22:50 UTC (permalink / raw) To: Christophe Raffalli; +Cc: kirillkh, oleg, caml-list On Wed, 2007-10-03 at 22:39 +0200, Christophe Raffalli wrote: > So the story is by saying (wrongly) that it is too heavy to anottate > arrow types with exceptions, > making the arrow type a ternary type construct, ML is missing a lot ... To be bold I propose type theorists have got it totally wrong. Goedel's theorem says that any type system strong enough to describe integer programming is necessarily unsound. All advanced programming languages have unsound type systems of necessity. Some falsely claim soundness by denying the expression of certain type information (eg array bounds or the type of integers excluding zero). I want an unsound type system! It much better than the useless but 'sound' type system of Python, in which the type inference engine decides all values have type Object and proves in vacuuo that all programs are type-safe, only to do the dependent type checks at run time anyhow -- a cheat known as dynamic typing. It is better to admit from the start that type systems can and MUST be unsound, and allow programmers to write known correct programs with expressive typing which no type system could type check, than to turn programmers off by rejecting their valid code. The cost is some invalid code will be accepted, but there is no help for it: the type system has to be unsound or it is of no practical use at all (Ok, I exaggerate, predicate calculus is complete and useful .. algebraic typing is the equivalent). In particular, the ability to write proper type annotations such as divide: int * (int - {0}) -> int and fail to reject programs which violate the typing is an essential and useful feature. Later, some programs may be properly rejected early instead of late when some smart type theorist extends the capabilities of the compiler, or the programmer learns how to re-express the typing so the existing algorithms catch more faults. Languages like Ocaml make significant advances in type checking capability, but users and theorists incorrectly laugh at the weak and unsound type system of C. In fact, the idea of C is the right one. We know the type system is unsound. It is essential. It is the very reason C lives on. Newer compilers have better error detection, in the meantime C doesn't stop you writing your code. C does this right: you can use a cast to override the type checks OR you can simply exploit the unsoundness directly. The latter is preferable because later versions of the compiler may be smart enough to catch real errors which the casts would always defeat. It's time to turn type theory on its head. Forget about whether the typing is sound, give me EXPRESSION first and worry about checking second. Accept Goedel: the unsoundness is *essential* and thus must not be an excuse for failure to express. Let me write: divide: int * (int - {0}) -> int and I may catch a bug using the human brain, or later the compiler may be improved and catch more bugs automatically. The fact it will never catch all these bugs is irrelevant because unsoundness is an essential requirement of expressive type systems. Stop CHEATING by refusing to allow me to write types you can't check -- because this forces ME as the programmer to cheat on the type annotations: divide: int * int -> int hd : 'a list -> 'a -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 22:50 ` Unsoundness is essential skaller @ 2007-10-03 23:13 ` Jacques Carette 2007-10-04 1:24 ` skaller 2007-10-03 23:13 ` Vincent Aravantinos ` (3 subsequent siblings) 4 siblings, 1 reply; 41+ messages in thread From: Jacques Carette @ 2007-10-03 23:13 UTC (permalink / raw) To: skaller; +Cc: caml-list skaller wrote: > To be bold I propose type theorists have got it totally wrong. > > Goedel's theorem says that any type system strong enough to > describe integer programming is necessarily unsound. > No, that's wrong. Any *complete* type system that strong is unsound. It says nothing about incomplete systems. My position is that looking for decision procedures everywhere is what is blocking real progress. People doing dependent types have gotten over most of that. > I want an unsound type system! No you don't, you want an incomplete one. You want one where the type system will tell you when you are obviously wrong, and will ask you for a proof when it's not sure. If you insist on unsound, then when the type system doesn't know, it might let things through anyways, and then all bets are off. I don't want that. > It much better than the useless > but 'sound' type system of Python, in which the type inference > engine decides all values have type Object and proves > in vacuuo that all programs are type-safe, only to do the > dependent type checks at run time anyhow -- a cheat known > as dynamic typing. > Again, I disagree. It's much better to do most type checks statically, and then to residualize some type checks to run-time if you absolutely must. This is roughly what my Master's student Gordon Uszkay did for a "scientific computation" language, using CHRs. Unfortunately, his work was already way too ambitious as it was, so all he succeeded in doing is an implementation [that works], but no formal proofs. > In particular, the ability to write proper type annotations > such as > > divide: int * (int - {0}) -> int > > and fail to reject programs which violate the typing is an > essential and useful feature. I would rather say that what should be done is that run-time type checks should be residualized into the program, so that no unsound program would be allowed to run to completion, an assertion would be triggered first. > In fact, the idea of C is the right one. When I was forced to write a C program (after enjoying Ocaml so much), and even with gcc -W -Wall -Werror -pedantic something.c I got a clean compile which, when run, core dumped, I was seriously unhappy. > Stop CHEATING by refusing to allow > me to write types you can't check -- because this forces > ME as the programmer to cheat on the type annotations: > > divide: int * int -> int > hd : 'a list -> 'a > Here we agree. Both of those types are 'cheating'. Jacques ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 23:13 ` [Caml-list] " Jacques Carette @ 2007-10-04 1:24 ` skaller 2007-10-04 11:26 ` David Allsopp 0 siblings, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 1:24 UTC (permalink / raw) To: Jacques Carette; +Cc: caml-list On Wed, 2007-10-03 at 19:13 -0400, Jacques Carette wrote: > skaller wrote: > > To be bold I propose type theorists have got it totally wrong. > > > > Goedel's theorem says that any type system strong enough to > > describe integer programming is necessarily unsound. > > > No, that's wrong. Any *complete* type system that strong is unsound. > It says nothing about incomplete systems. You're right, I have assumed a complete system cannot describe the integer programming. Is that not so? > > I want an unsound type system! > No you don't, you want an incomplete one. You want one where the type > system will tell you when you are obviously wrong, and will ask you for > a proof when it's not sure. If you insist on unsound, then when the > type system doesn't know, it might let things through anyways, and then > all bets are off. I don't want that. Ah, but that is what I *am* arguing for. The 'reasoning' is simply that 'the programmer knows best' -- when the type system doesn't. The evidence is: programming languages with dynamic or unsound typing eg Python, C, are vastly more popular than those with strong typing. Now, my (quite disputable) claim is that the reason for that is that the strong typing people prefer to reject correct programs than accept ones which cannot be proven correct, but this belief is *demonstrably* fallacious. As I demonstrated with simple examples, the type system ALREADY lets incorrectly typed programs through. This fact is hidden by theoretical mumbo-jumbo. It's time the theorists woke up. Leaving out (int-{0}) as a type simply because it would make the type system unsound does not enhance the reliability of the program: either way, without the annotation and a sound type system or with the annotation and an unsound system, it is possible to have a division by 0. The difference is that the unsound system can be improved, and the human brain can do type-checking too. So the unsound system is better because it subsumes the sound one. Nothing is lost in the unsound system. NEITHER system guarantees correctness, and the unsound system still rejects at least the same set of incorrect programs, but possibly more. Ocaml type system is ALREADY unsound: any division by zero or array bounds check exception provides that conclusively. Type systems will NEVER be able to prove all programs are correct. Requiring type safety, i.e. soundness, is simply an obstacle, not an aid. Correctness and type-safety from soundness aren't the same thing. It is better to put more information in the type system, to be more expressive and declarative and accept unsoundness, than to be limited in one's declarative description of executable code, so that in fact the typing is WRONG, in which case the soundness of the type system is of no use in proving correctness! I am arguing in favour of a much richer and more expressive type system, EVEN IF it is not known how to prove type-correctness, and indeed EVEN IF it CAN be proven that there exist cases which are undecidable! > Again, I disagree. It's much better to do most type checks statically, > and then to residualize some type checks to run-time if you absolutely > must. I don't see how I disagree with that. Indeed, that is very much my point! You check what can be checked early, but unless the compiler can PROVE that the code is incorrect, it should not reject it. Unsoundness doesn't imply incorrectness. Any failure caught at runtime by a 'residualised' check proves the type system is unsound. So actually you agree with my point. If indeed the type system were sound there would necessarily not be any need to generate any such run time checks. [Note: this does not mean run time type information isn't required, eg constructor indices, array bounds, etc: run time type calculations subsume mere type-checks] > > In particular, the ability to write proper type annotations > > such as > > > > divide: int * (int - {0}) -> int > > > > and fail to reject programs which violate the typing is an > > essential and useful feature. > I would rather say that what should be done is that run-time type checks > should be residualized into the program, so that no unsound program > would be allowed to run to completion, an assertion would be triggered > first. I told you: you're agreeing with my claim. However it is slightly confused: a program can be correct or not, it cannot be unsound. It is the type system which can be sound or not. So I am going to assume you mean: a program with suspicious typing for which a type-safety proof cannot be found at compile time should have a run time check to ensure the fault consequent of the unsoundness is caught and diagnosed ASAP at run time. I don't dispute the ability to generate such checks is useful, however I raise these issues: 1. What if you cannot generate the checks? 2. Just because the checks pass doesn't mean the program is correct > > In fact, the idea of C is the right one. > When I was forced to write a C program (after enjoying Ocaml so much), > and even with > gcc -W -Wall -Werror -pedantic something.c > I got a clean compile which, when run, core dumped, I was seriously > unhappy. And I got a Not_found error in my Ocaml program recently which took three days to locate. I don't see any qualitative difference. There is a difference of 'degree' which confusingly is a quality issue: better diagnostics, earlier detection, etc. But the bottom line is an uncaught exception in Ocaml and a null pointer dereference in C both cause an abnormal termination symptomatic of an incorrect program (not necessarily due to a typing error). > > Stop CHEATING by refusing to allow > > me to write types you can't check -- because this forces > > ME as the programmer to cheat on the type annotations: > > > > divide: int * int -> int > > hd : 'a list -> 'a > > > Here we agree. Both of those types are 'cheating'. Yes, but your solution might look like this: divide: int * (int \ {0}) -> int with static check on int, and residualised check for a zero divisor .. and for hd, similar... Hey, Ocaml does those checks NOW! SO what's the difference?? The difference is that the system with (int \ {0}) is unsound, but more expressive. My argument is simply that this is BETTER. Not allowing this has no real utility other than to allow theorists to argue the type system is sound. It has no benefits, and many downsides. Perhaps you see a problem where some typing notation is so hard it cannot even be checked at run time? This can surely happen. My answer is: SO WHAT? The programmer is going to code the algorithm ANYHOW. They will either use CHEAT types, in which case the type safety provides no benefit OR, MUCH WORSE .. they're go off and write the program in Python or C instead. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [Caml-list] Unsoundness is essential 2007-10-04 1:24 ` skaller @ 2007-10-04 11:26 ` David Allsopp 2007-10-04 12:45 ` Vincent Hanquez 0 siblings, 1 reply; 41+ messages in thread From: David Allsopp @ 2007-10-04 11:26 UTC (permalink / raw) To: caml-list > Ah, but that is what I *am* arguing for. The 'reasoning' is simply > that 'the programmer knows best' -- when the type system doesn't. "the programmer knows best" is one of the founding principles of BCPL!! I'm not sure I agree, though - IMO Vincent is correct that being forced to express things "properly" results in better code in the long run. Try writing any substantial amount of BCPL[*]... > The evidence is: programming languages with dynamic or unsound > typing eg Python, C, are vastly more popular than those with > strong typing. I'm not at all convinced that dynamic/unsound typing is the reason for the popularity of C, etc - I've never met a C programmer whose eyes didn't pop out on stalks when you explain that Ocaml cannot reference a null pointer (not that that has ever caused a Damascene-road conversion to the language, either!). <joke> C and Python's popularity is more down to needing ever more programmers to debug the work of the previous programmers, right? :o) </joke> Personally, whenever I go back to C, the novelty of the relaxed type system is instantly worn away on the first tricky-to-repeat core dump... at least an Ocaml exception has a cat in hell's chance of being found systematically! David * With apologies and due deference to Martin Richards if he reads this list! ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 11:26 ` David Allsopp @ 2007-10-04 12:45 ` Vincent Hanquez 2007-10-04 15:07 ` skaller 0 siblings, 1 reply; 41+ messages in thread From: Vincent Hanquez @ 2007-10-04 12:45 UTC (permalink / raw) To: David Allsopp; +Cc: caml-list On Thu, Oct 04, 2007 at 12:26:53PM +0100, David Allsopp wrote: > Personally, whenever I go back to C, the novelty of the relaxed type > system is instantly worn away on the first tricky-to-repeat core dump... at > least an Ocaml exception has a cat in hell's chance of being found > systematically! That's sadly not true. GC bugs in some bindings are usually hard to find ! Cheers, -- Vincent Hanquez ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 12:45 ` Vincent Hanquez @ 2007-10-04 15:07 ` skaller 0 siblings, 0 replies; 41+ messages in thread From: skaller @ 2007-10-04 15:07 UTC (permalink / raw) To: Vincent Hanquez; +Cc: David Allsopp, caml-list On Thu, 2007-10-04 at 14:45 +0200, Vincent Hanquez wrote: > On Thu, Oct 04, 2007 at 12:26:53PM +0100, David Allsopp wrote: > > Personally, whenever I go back to C, the novelty of the relaxed type > > system is instantly worn away on the first tricky-to-repeat core dump... at > > least an Ocaml exception has a cat in hell's chance of being found > > systematically! > > That's sadly not true. GC bugs in some bindings are usually hard to find ! I think David's point is that many faults in C are diagnosed, if at all, by a very hard to analyse output (a core dump). Whereas in Ocaml more bugs are caught at compile time, and, often a bug at run time has some simple abstract information such as an exception constructor name, which help in pinpointing the problem. I don't think the claim was *elimination* as much as *improvement*. However I thin David is missing my argument if he's thinking I am arguing for a more relaxed type system: on the contrary I want an even tighter type system. The problem is that the cost is likely to be unsoundness -- in the process of making the type system more expressive, we're bound to be forced to let some ill-typed programs through because it is no longer feasible to prove well-typedness in all cases. My argument is that this just isn't a problem to worry about: the only difference is that existing buggy programs which were previously judged type correct, are no longer decided as type correct. In some cases a program will be let through by BOTH type systems, and in others the more expressive system will find the error, so the fact that the type system is unsound is not a problem: our confidence in the correctness of the program is *enhanced* despite the unsoundness. Furthermore, my program which today is accepted may be rejected tomorrow when a theorist finds some way to reduce the unsoundness by catching more cases. This is impossible if you don't let me write the annotations just because you can't prove the well typedness right now! BTW: when I say 'type system' and 'soundness' I mean *static type checking*. I do not consider dynamic typing as a type system in this sense. Any type test at run time is instant proof of unsoundness of the type system: an ill typed program has been allowed to escape to run time. The fact that a policeman is set to catch the inmate who escaped from jail does not in any way diminish the fact the inmate indeed escaped, and the jail security system was unsound (Ouch .. new season of Prison Break .. :) -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 22:50 ` Unsoundness is essential skaller 2007-10-03 23:13 ` [Caml-list] " Jacques Carette @ 2007-10-03 23:13 ` Vincent Aravantinos 2007-10-04 1:49 ` skaller 2007-10-03 23:28 ` Joshua D. Guttman ` (2 subsequent siblings) 4 siblings, 1 reply; 41+ messages in thread From: Vincent Aravantinos @ 2007-10-03 23:13 UTC (permalink / raw) To: skaller; +Cc: Christophe Raffalli, oleg, caml-list Le 4 oct. 07 à 00:50, skaller a écrit : > On Wed, 2007-10-03 at 22:39 +0200, Christophe Raffalli wrote: > >> So the story is by saying (wrongly) that it is too heavy to anottate >> arrow types with exceptions, >> making the arrow type a ternary type construct, ML is missing a >> lot ... > > To be bold I propose type theorists have got it totally wrong. > ... > expressive type systems. Stop CHEATING by refusing to allow > me to write types you can't check -- because this forces > ME as the programmer to cheat on the type annotations: > > divide: int * int -> int > hd : 'a list -> 'a If you allow everything (such as the "type expressive" C you are envisaging), the programmer will be tempted to use this "everything" whereas he could achieve the same with a "bounded" language. And in this case I bet the programmer won't do things that will ever be "type theoretic friendly", whatever progress in type theoretics will be. To my eyes it looks like many things that appeared in other languages to appeal the programmers, but that could be achieved in other (did I say better ?) ways. If you allow everything, people will be tempted to do anything... And any progress in computer science will never catch the gap. I think it's a good thing to constrain the programmer. How many times I thought "that's a pity I can't do this *as I want* in ocaml". And then after having been forced to think of another way to achieve my goal *within the constraints of ocaml*, I ended with something like "woah, actually it's better this way!". Cheers, Vincent ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 23:13 ` Vincent Aravantinos @ 2007-10-04 1:49 ` skaller 0 siblings, 0 replies; 41+ messages in thread From: skaller @ 2007-10-04 1:49 UTC (permalink / raw) To: Vincent Aravantinos; +Cc: Christophe Raffalli, oleg, caml-list On Thu, 2007-10-04 at 01:13 +0200, Vincent Aravantinos wrote: > Le 4 oct. 07 à 00:50, skaller a écrit : > > To be bold I propose type theorists have got it totally wrong. > > ... > > expressive type systems. Stop CHEATING by refusing to allow > > me to write types you can't check -- because this forces > > ME as the programmer to cheat on the type annotations: > > > > divide: int * int -> int > > hd : 'a list -> 'a > > If you allow everything (such as the "type expressive" C you are > envisaging), the programmer will be tempted to use this "everything" > whereas he could achieve the same with a "bounded" language. Yes, this is a valid criticism. Can you please help refine my idea to take this into account? What we want is to push the programmer into using the most checkable form, and only let them 'escape' if it is really necessary (I hope you agree with that summary!) But I have no idea how to do that in a coherent way. A kind of Occam's Razor of programming .. :) In C++, this is done by encouraging programmers not to use casts, but still allowing them, and indeed, providing a more refined and pointed set of casts as well: static_cast, dynamic_cast, const_cast, reinterpret_cast These are long winded (deliberately) and frowned upon so there is both mechanical (I hate typing) and psychological (peer pressure, pride, etc) pressure NOT to use casts, and this is encourage by the fact that C++ needs a LOT LESS casts than C. In Ocaml .. Obj.magic is 'evil' and not documented.. But this is a really WEAK form of pressure. > To my eyes it looks like many things that appeared in other languages > to appeal the programmers, but that could be achieved in other (did I > say better ?) ways. If you allow everything, people will be tempted > to do anything... And any progress in computer science will never > catch the gap. Yes, but the problem now is that all these new languages are coming out and the designed IGNORE all the good academic work. Java, Ruby .. to name two examples of *new* rubbish which are immensely popular, whilst Ocaml and Haskell haven't taken off. > I think it's a good thing to constrain the programmer. No dispute. I'm not arguing for NO constraints. In fact it is the other way around. I'm arguing to allow the programmer to apply MORE constraints in the form of more expressive types EVEN IF THESE CONSTRAINTS CANNOT BE ENFORCED. > How many times > I thought "that's a pity I can't do this *as I want* in ocaml". And > then after having been forced to think of another way to achieve my > goal *within the constraints of ocaml*, I ended with something like > "woah, actually it's better this way!". Yes. I have to tell you that I use this idea systematically as a programming technique! However many things annoy me, some of which I have tried to fix in Felix. One of them is that modules/functor do not allow expression of semantic rules: Felix has typeclasses WITH semantic rules. Although the rules are limited, Felix can actually generate a vast battery of axiom checks, and, it currently emits theorem claims in Why encoding which allows the claims to be checked by various theorem provers, including Ergo. None of this comes close to doing what I actually need in the Ocaml code of the compiler itself, which is a to enforce invariants of the term rewriting system in the type system. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 22:50 ` Unsoundness is essential skaller 2007-10-03 23:13 ` [Caml-list] " Jacques Carette 2007-10-03 23:13 ` Vincent Aravantinos @ 2007-10-03 23:28 ` Joshua D. Guttman 2007-10-04 1:52 ` skaller 2007-10-04 15:31 ` Lukasz Stafiniak 2007-10-04 17:56 ` rossberg 4 siblings, 1 reply; 41+ messages in thread From: Joshua D. Guttman @ 2007-10-03 23:28 UTC (permalink / raw) To: skaller; +Cc: Joshua D. Guttman, caml-list skaller <skaller@users.sourceforge.net> writes: > Goedel's theorem says that any type system strong enough > to describe integer programming is necessarily unsound. Are you sure that's what it *says*? I thought I remembered it stated differently. Poor old guy. Worked so hard to be precise, and now everybody attributes all sorts of things to him. Joshua -- Joshua D. Guttman The MITRE Corporation ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 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 0 siblings, 2 replies; 41+ messages in thread From: skaller @ 2007-10-04 1:52 UTC (permalink / raw) To: Joshua D. Guttman; +Cc: caml-list On Wed, 2007-10-03 at 19:28 -0400, Joshua D. Guttman wrote: > skaller <skaller@users.sourceforge.net> writes: > > > Goedel's theorem says that any type system strong enough > > to describe integer programming is necessarily unsound. > > Are you sure that's what it *says*? I thought I remembered > it stated differently. I paraphrased it, deliberately, in effect claiming an analogous situation holds with type systems. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 1:52 ` skaller @ 2007-10-04 2:35 ` Brian Hurt 2007-10-04 7:46 ` Christophe Raffalli 1 sibling, 0 replies; 41+ messages in thread From: Brian Hurt @ 2007-10-04 2:35 UTC (permalink / raw) To: skaller; +Cc: Joshua D. Guttman, caml-list On Thu, 4 Oct 2007, skaller wrote: > On Wed, 2007-10-03 at 19:28 -0400, Joshua D. Guttman wrote: >> skaller <skaller@users.sourceforge.net> writes: >> >>> Goedel's theorem says that any type system strong enough >>> to describe integer programming is necessarily unsound. >> >> Are you sure that's what it *says*? I thought I remembered >> it stated differently. > > I paraphrased it, deliberately, in effect claiming an analogous > situation holds with type systems. > I'm not sure that's correct- I thought it was that any type system sufficiently expressive enough (to encode integer programming) could not be gaurenteed to be able to be determined in the general case- that the type checking algorithm could not be gaurenteed to halt, in other words, and the computing equivelent of Godel's theorem is the halting problem. The dividing line, as I understand it, is non-primitive recursion. So Ocaml's type system, which is not Turing complete, is gaurenteed to terminate eventually (it may have regretable big-O behavior, including an nasty non-polynomial cost algorithm for unification, but it will complete if you let it run long enough, which may be decades...). Haskell's type system, by comparison, is Turing complete, so it's not gaurenteed to ever halt/terminate in the general case. One advantage Haskell has over Ocaml is that Haskell has a Turing complete type system- on the other hand, one advantage Ocaml has over Haskell is that Ocaml doesn't have a Turing complete type system... :-) I am not an expert, tho. Brian ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 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 1 sibling, 1 reply; 41+ messages in thread From: Christophe Raffalli @ 2007-10-04 7:46 UTC (permalink / raw) To: skaller; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 3140 bytes --] skaller a écrit : > On Wed, 2007-10-03 at 19:28 -0400, Joshua D. Guttman wrote: >> skaller <skaller@users.sourceforge.net> writes: >> >>> Goedel's theorem says that any type system strong enough >>> to describe integer programming is necessarily unsound. > > I paraphrased it, deliberately, in effect claiming an analogous > situation holds with type systems. > Not unsound, incomplete ! you mixup first and second incompleteness theorem. Let's clarify ? - first if a type system does not contain arithmetic nothing can be said (this implies ML), but in this case, the meaning of complete needs to be clarified. Indeed, there are complete type system ... - The 1st incompleteness theorem states that no theory containing arithmetic is complete. This means that there will always be correct programs that your type system can not accept. However, I thing a real program that is not provably correct in lets say ZF, does not exists and should be rejected. you do not accept a program whose correctness is a conjecture (do you ?) - The second incompleteness theorem, states that a system that proves its own consistency is in fact inconsistent. For type system (strong enough to express arithmetic, like ML with dependant type, PVS, the future PML, ..). This means that the proof that the system is consistent (the proof that "0 = 1 can not be proved") can not be done inside the system. However, the proof that your implementation does implement the formal system correctly can be done inside the system, and this is quite enough for me. - The soundness theorem for ML can be stated as a program of type "int" will - diverge - raise an exception - or produce an int I think everybody except LISP programmers ;-) want a sound type system like this. OK replace everybody by I if you prefer ... For PML, we are more precise : exception and the fact the a program may diverge must be written in the type. - ML type system is sometimes too incomplete, this is why the Obj library is here. However, the use of Obj is mainly here because ML lacks dependant types. In fact, the main use of Obj is to simulate a map table associating to a key k a type t(k) and a value v:t(k). - All this says that a type-system only accepting proved programs is possible and a good idea (it already exists). The question for researcher is how to produce a type system where the cost of proving is acceptable compared to the cost of debugging, and this stars to be the case for some specific application, but we are far from having to remove the word "bug" from our vocabulary ;-) -- Christophe Raffalli Universite de Savoie Batiment Le Chablais, bureau 21 73376 Le Bourget-du-Lac Cedex tel: (33) 4 79 75 81 03 fax: (33) 4 79 75 87 42 mail: Christophe.Raffalli@univ-savoie.fr www: http://www.lama.univ-savoie.fr/~RAFFALLI --------------------------------------------- IMPORTANT: this mail is signed using PGP/MIME At least Enigmail/Mozilla, mutt or evolution can check this signature. The public key is stored on www.keyserver.net --------------------------------------------- [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 252 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 7:46 ` Christophe Raffalli @ 2007-10-04 8:56 ` Arnaud Spiwack 2007-10-04 14:49 ` skaller 2007-10-04 15:04 ` Andrej Bauer 0 siblings, 2 replies; 41+ messages in thread From: Arnaud Spiwack @ 2007-10-04 8:56 UTC (permalink / raw) To: caml-list Hi everybody, Christophe already said much of what I have to do, but it's compulsively impossible to me to avoid posting on such a thread. My own psychopathologies coerce me into meddling into here. First of all, as some sort of an introductory thing, I'd like to mention that Java is probably the currently most popular language among programmers, and it's strongly typed. Indeed, there are quite a few unsafe feature (null pointers, down casting), but they are gradually removed (well, I guess null pointers won't ever): since the addition of generics wild downcasting to use generic structures is largely deprecated, if one would provide with a primitive ternary guarded cast operator, one wouldn't have to resort to write it by hand "if (blah.isClass...", etc... Anyway, back to Mr. Gödel and his theorem. What he stated indeed is that truth and provability never coincide (provided we're talking of something at least as expressive as arithmetic). That is, as some people already mentionned: either everything can be proved, or there is at least a statement A such that neither A is provable neither its negation. Still there is something peculiar in the interpretation of Gödel theorem, since if we are in a classical logical system (where ~~A (not not A) and A are equivalent). If neither A nor ~A are provable, then both can be "the real one". By that I mean that both can be chosen as true, without impacting the consistency of the system (quick proof sketch : A -> ~A is equivalent to A -> (A -> False) which is equivalent to A&A -> False wich is equivalent to ~A). A conclusion I can draw from that is that we don't care about what is true, we care about what is provable, since it is at least welle defined, where truth is very much unclear (an example of such weirdness is the axiom of choice, which is a very pratical axiom in classical mathematics, and widely accepted. Except when you are doing probabilities where it is very convenient to have the "measurability axiom" stating that "everything is mesurable" (more or less) and which contradicts the axiom of choice). Now let's move to programming again. Type systems can be arbitrarily complex, see for instance, Coq, Agda2, Epigram, PML and many other that I'm less familiar with. In this language, evidences show that everything one needs to prove for proving a program (partially) correct, is provable. There we must draw a clear line between two concept which have been a bit mixed up in this thread : provability and decidability. Of course, it is not possible to decide in all generality that whoever integer is non-zero, thus a type system able to express (int -> int-{0} -> int) as a type for division cannot decide type checking without extra information. The extra information is no more than a proof that we never provide an 0-valued integer (at each application). And curry-howard isomorphism allows to stick it inside the type system. That's what Type Theorist yearn for (by the way that is cool because many runtime check consume time unneedlessly, and time is money, and money is precious). Of course, there is still a lot of work to do around these. But this is more than promissing, and one should be able to never need unsafe features (though there actually is a more or less unsafe feature inherently in these type systems, it's called "axioms", since you can generaly enhance the theory with any additional claim. However axioms are usually kept out of very sensitive areas). At any rate, this does not say anything about the mostly untype languages. It is a different issue, typed vs untyped or decidable type inference vs more expressiveness in type system. The untyped world has its perks, especially C, which allow quite a few low level manipulation which are very useful. What I mean here is that if we need types (and I believe that a vast majority of programming application do), then we should have as expressive typing as possible, and not need to rely on unsafe feature which give headaches and segfaults. I realize that I got lost in my way, so I'll stop here, but I may be back (this is a much more prudent claim than that of another AS) in followups ;) . Arnaud Spiwack Christophe Raffalli a écrit : > skaller a écrit : > >> On Wed, 2007-10-03 at 19:28 -0400, Joshua D. Guttman wrote: >> >>> skaller <skaller@users.sourceforge.net> writes: >>> >>> >>>> Goedel's theorem says that any type system strong enough >>>> to describe integer programming is necessarily unsound. >>>> >> I paraphrased it, deliberately, in effect claiming an analogous >> situation holds with type systems. >> >> > > Not unsound, incomplete ! > you mixup first and second incompleteness theorem. Let's clarify ? > > - first if a type system does not contain arithmetic nothing can be said > (this implies ML), but in this case, the meaning of complete needs to be clarified. > Indeed, there are complete type system ... > > - The 1st incompleteness theorem states that no theory containing > arithmetic is complete. This means that there will always be correct programs > that your type system can not accept. However, I thing a real program that > is not provably correct in lets say ZF, does not exists and should be rejected. > you do not accept a program whose correctness is a conjecture (do you ?) > > - The second incompleteness theorem, states that a system that proves its own > consistency is in fact inconsistent. For type system (strong enough to express > arithmetic, like ML with dependant type, PVS, the future PML, ..). This means > that the proof that the system is consistent (the proof that "0 = 1 can not be proved") > can not be done inside the system. However, the proof that your implementation > does implement the formal system correctly can be done inside the system, and > this is quite enough for me. > > - The soundness theorem for ML can be stated as a program of type "int" will > - diverge > - raise an exception > - or produce an int > I think everybody except LISP programmers ;-) want a sound type system like this. > OK replace everybody by I if you prefer ... For PML, we are more precise : exception > and the fact the a program may diverge must be written in the type. > > - ML type system is sometimes too incomplete, this is why the Obj library is here. > However, the use of Obj is mainly here because ML lacks dependant types. In fact, > the main use of Obj is to simulate a map table associating to a key k a type t(k) and > a value v:t(k). > > - All this says that a type-system only accepting proved programs is possible and > a good idea (it already exists). The question for researcher is how to produce a > type system where the cost of proving is acceptable compared to the cost of debugging, > and this stars to be the case for some specific application, but we are far from > having to remove the word "bug" from our vocabulary ;-) > > > ------------------------------------------------------------------------ > > _______________________________________________ > Caml-list mailing list. Subscription management: > http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list > Archives: http://caml.inria.fr > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 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 15:04 ` Andrej Bauer 1 sibling, 2 replies; 41+ messages in thread From: skaller @ 2007-10-04 14:49 UTC (permalink / raw) To: Arnaud Spiwack; +Cc: caml-list On Thu, 2007-10-04 at 10:56 +0200, Arnaud Spiwack wrote: > Hi everybody, > Still there is something peculiar in the interpretation of Gödel > theorem, since if we are in a classical logical system (where ~~A (not > not A) and A are equivalent). If neither A nor ~A are provable, then > both can be "the real one". By that I mean that both can be chosen as > true, without impacting the consistency of the system (quick proof > sketch : A -> ~A is equivalent to A -> (A -> False) which is equivalent > to A&A -> False wich is equivalent to ~A). > > A conclusion I can draw from that is that we don't care about what is > true, we care about what is provable, since it is at least welle > defined, This is my point. Theorists have this all wrong. I'm a programmer. I do NOT really care if my program is provably correct. Sure, it would be nice to have such a proof, but the lack of one will not stop me writing the program! What I care about is that the program works. Now, suppose I code some types in my program, and the type system cannot prove I have respected them. Incompleteness ensures this can happen (given a sufficiently powerful type system). Pragmatics indicates this is also possible: the proof may indeed be constructible but take too long to construct to be practical. Should it accept or reject the program? My claim is that it should accept the program. It should only reject programs which can be proven incorrect. Now, I want you to hold on before disputing that claim, because there is more to the reasoning to come. The purpose of typing is to assist in showing a program is incorrect. We know for sure that in principle and practice there will be well typed incorrect programs, so there is no issue of proving all programs correct. The question is, should we strengthen the type systems we use to be more descriptive? There is a problem doing this. If we make the type system descriptive enough, there is a possibility we will be able to reject more programs -- this is good! But it is also likely that we will lose the ability to prove the typing is correct. What should we do? If we reject the program, the programmer will be annoyed, if we accept it, the type system is unsound, because in accepting it, we risk accepting programs which are not well typed, and therefore not correct. Now, please observe that with a stronger type system, we are going to reject more programs. That is the point. But we are ALSO going to be unable to decide the well typedness of many programs, for either incompleteness or pragmatic reasons. It simply isn't feasible to reject these programs simply because a proof of well-typedness cannot be constructed: and there is no possibility of disputing this claim because it is what programming languages like Ocaml do right now: they generate run time checks precisely because they cannot ensure correctness. It's already a known fact that today, we cannot ensure certain things like array bounds and zero division statically. So the question is, whether array length and non-zero integers should be expressible in the type systems today. And my answer is YES PLEASE. A type system with that expression MUST BE UNSOUND. I hope this argument is not too hard to follow: if you make the type system expressive enough, right now, then it MUST BE UNSOUND because we cannot have the type system rejecting the many correct programs I can and do write where I (think I) know I'm never going to divide by zero, simply because the type system cannot prove my belief. There is no issue that the powerful type system must be unsound. That is not the question or the claim. The question is: should compiler writers introduce powerful enough type systems that can express things like non-zero integers or array index correctness, KNOWING FOR SURE THAT TO DO SO MANDATES UNSOUNDNESS. There's no question such powerful type systems have to be unsound, at least today. That isn't in dispute! The question is whether we should introduce such rich and expressible notations anyhow! My claim is YES WE SHOULD. Because Arnaud is quite wrong in his belief that 'what we should care about is provability'. That is what theoreticians care about, but it is NOT the domain in which programmers operate (unless they're type systems programmers of course! :) [PS: of course I do *care* about provability, but I'm not willing to give up programming just because I can't prove everything I code is correct] So finally I will give an example: I cannot write this: hd : 'a non-empty-list -> 'a divide: int * non-zero-int -> int in Ocaml at the moment. Should I be able to?? If you say YES, you will note the Ocaml type system would become unsound. Ocaml simply cannot prove in all cases that an integer value is non-zero, nor that a list is non-empty. We do not reject programs that apply 'hd' just because of this. Heck: hd and divide ARE PART OF THE CORE LIBRARY!!!! My point is: NOTHING IS LOST BY MAKING THE TYPE SYSTEM UNSOUND WITH THIS EXTENSION. Indeed in SOME cases Ocaml may indeed be able to prove wrong typing, so we GAIN something from the point of view of machine verification. And the human programmer gains something too, because they too may find errors, even ones the type system cannot, and it could easily make the program semantics easier to understand, if the interface type annotations were richer. So my belief is that theoreticians are doing the programming industry a DISSERVICE by insisting on sound typing, because in so doing they're greatly limiting the expressiveness of the type system. There is no benefit in it. That is the point. A proof of well-typedness is NOT a proof of correctness in the first place. I do not care that the type system cannot prove well typedness because that is not its job: its job is to prove a program INCORRECT by proving wrong typing. Making the type system unsound by extending the expressiveness can be done without failing to reject programs which are currently rejected. Take Ocaml and add non-zero integers, and allow it to accept programs where the non-zeroness cannot be proven, and we are no worse off than now, where the same fact applies: Ocaml ALREADY allows such programs. Much as we'd like to be able to guarantee that a program using non-zero integer type is well typed, it is better to let such a program pass, than to compromise the expressiveness of the type system JUST BECAUSE THEORETICIANS ARE SO CONFUSED ABOUT WHAT THE PURPOSE OF THE TYPE SYSTEM IS THAT THEY REFUSE TO ALLOW AN UNSOUND ONE (of course I'm definitely not meaning to be offensive here!) If you think a type system has to be sound, you do not understand that the purpose is to catch errors early, and if not diagnose them late, and we wish to catch as many as possible. We are therefore COMPELLED to introduce a richer type system, and there is no doubt such a system, at least today if not always, cannot be sound. BTW: I am not asking for 'non-zero-int' and 'non-empty-list' as actual features for Ocaml. There is still a real issue how to make the extensions to the type system in a general enough way. For example: int \ {0} looks better because subtraction is a fairly general operator, but there may be other more useful annotations. There certainly exist languages where the 'checking' system is 'unsound'. For example Eiffel and Felix both allow pre and post conditions on functions, and both generate run time checks, which are witness to unsoundness. It is merely pride of theoreticians that they claim a precondition is not type information. There is NO DOUBT in my mind a precondition is precisely a restriction on the set of input values to a function, and is definitely type information. Ocaml does not let you notate this**, although you can write an assert, but in Felix it is plain it is intended as type information: fun divide(x: int where x!=0): ... even though this is not encoded in the type signature because I do not know what to do with it. In Felix the typing is unsound, because it generates the non-zero test at run time. ** of course Ocaml DOES let you notate this now we have private types we can enforce the constraint in the constructor of a record, however this semi-abstract type is nominally typed, and not quite the same as a structural annotation like int \ {0} which is anonymously typed. However this enforcement is clearly an unsoundness of typing because the constraint isn't enforced at compile time. So this is a perfect example of a GOOD extension of the kind I desire which already introduces an unsoundness. The key point of the idea is in fact to clearly and pointedly restrict the unsoundness to the constructor. Using this, plus smartness of the type system, we may be able to: a) reject some programs which are clearly incorrect b) optimise away the check in other programs which are clearly correct c) accept a program where the type system cannot decide and generate runtime check as witness to the unsoundness This is GOOD. There should be more of it! The lack of soundness is not a problem -- it's ESSENTIAL to rejecting even more incorrect programs because there's no way to eliminate the unsoundness without eliminating the very expressiveness which allows more programs to be type checked and thus more to be rejected. What's more, it leads to better performance too. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [Caml-list] Unsoundness is essential 2007-10-04 14:49 ` skaller @ 2007-10-04 15:00 ` Harrison, John R 2007-10-04 15:29 ` Andrej Bauer 1 sibling, 0 replies; 41+ messages in thread From: Harrison, John R @ 2007-10-04 15:00 UTC (permalink / raw) To: caml-list For those who are really interested in what Goedel's theorems say, or who might enjoy a spirited demolition of various abuses of them inside and outside logic, let me recommend this book by the late Torkel Franzen: http://www.akpeters.com/product.asp?ProdCode=2388 Naturally, I'm not implying that anyone on this thread is guilty of inappropriate use of the theorems. John. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 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 16:37 ` skaller 1 sibling, 2 replies; 41+ messages in thread From: Andrej Bauer @ 2007-10-04 15:29 UTC (permalink / raw) To: skaller; +Cc: caml-list At the danger of repeating myself (for which I apologize), I would like to convince skaller that he does not want unsound type systems. (What skaller calls "sound" I call "safety property" in my previous post.) Skaller, you want something like this: (a) expressive power (dependent types, subsets, you-name-it) (b) soundness, in the following form: * the compiler rejects obvious nonsense * the result of a compilation is a program and a list of assertions which the compiler was unable to verify This I would call "controlled unsoundness" which at least allows the human to see what needs to be verified to guarantee soundness. It's much better than the sort of unsoundness that skaller seems to be advocating. There is actually a new minor point I want to make: you cannot postpone all problems with typechecking to runtime. Only very simple conditions, such as bounds checks, can be checked at runtime. It is very easy to come up with preconditions that are computationally unverifiable. For example, you might have a numerical method for zero-finding which only works if the input is a function satisfying a funky condition, e.g., "the function is convex". How are you going to check that at runtime? Or to give you a much more simplistic example: fun find_zero (f: int -> int where not (forall n:int, f(n) != 0)) { int i = 0; while (f(i) != 0) { i++; } return i; } How will you verify the precondition on f at runtime? In this case I would expect the compiler to list all uses of find_zero applied to functions which are not known not have a zero. Let the human worry. Andrej ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 15:29 ` Andrej Bauer @ 2007-10-04 16:25 ` skaller 2007-10-04 18:17 ` Arnaud Spiwack 2007-10-04 16:37 ` skaller 1 sibling, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 16:25 UTC (permalink / raw) To: Andrej.Bauer; +Cc: caml-list On Thu, 2007-10-04 at 17:29 +0200, Andrej Bauer wrote: > Skaller, you want something like this: > > (a) expressive power (dependent types, subsets, you-name-it) > > (b) soundness, in the following form: > * the compiler rejects obvious nonsense > * the result of a compilation is a program and a list of > assertions which the compiler was unable to verify Yes, I want something like that. > This I would call "controlled unsoundness" As an (eX) motorcyclist I can agree .. riding a bike is like having one continuous controlled road accident.. :) > which at least allows the > human to see what needs to be verified to guarantee soundness. It's much > better than the sort of unsoundness that skaller seems to be advocating. Sure, but my point does remain: the expressiveness is more or less paramount. It is not so much that I personally desire it or not, but that real programmers in the real world go out there and do whatever is necessary to make programs work. If you can produce a compiler with an expressive type system but cannot yet create a complete list of unproven assertions, that is still better than writing Python. In fact I write a lot of Python even now. I do not do so in ignorance of the value of static type checking! There is a good reason I choose it, for example for the Felix build system. It is not because I fear writing all the types Ocaml would require, but because the need for 'dynamic typing' in this kind of software and the lack of expressiveness in Ocaml type system makes Ocaml unsuitable. Please note I'm *trying* to explain the reason, but probably haven't got it right. The point is, in the manifesto it should go like: expressiveness first, then generating proof obligations, and also with time, improving the automatic provers. The key thing is not to restrict expressiveness just because the type system cannot fully cope.. making the typing more expressive has many benefits by itself. A stupid one: how can theoreticians test the efficacy of a new algorithm with real world case data? -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 16:25 ` skaller @ 2007-10-04 18:17 ` Arnaud Spiwack 2007-10-04 20:54 ` skaller 0 siblings, 1 reply; 41+ messages in thread From: Arnaud Spiwack @ 2007-10-04 18:17 UTC (permalink / raw) To: caml-list > Sure, but my point does remain: the expressiveness is more or less > paramount. It is not so much that I personally desire it or not, > but that real programmers in the real world go out there and do > whatever is necessary to make programs work. > That would be wonderful if they did work... Unfortunately to my knowledge, a software is a mere collection of bugs, glued together with a couple of features. Or perhaps I'm being a little optimistic here :p . > A stupid one: how can theoreticians test the efficacy of a new > algorithm with real world case data? > This is obviously not possible (if I understand the question) since real world data don't obey any known law. However they can be modelized for further use. Anyway that is not what you were talking about and I think the discussion got confused due to the wild mix of different notions. One interpretation of what you suggest is to replace pieces of proof by run-time assertions, this sounds a plausible idea, though this is probably not a good thing to do for a finished product. It could however allow the program to be tested before one tries to prove it. There are various other ways to do it, though. Anyway, just be aware that having a more powerful type system usually means much more program that type. Contrary to what you seem to fear. Arnaud Spiwack ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 18:17 ` Arnaud Spiwack @ 2007-10-04 20:54 ` skaller 2007-10-04 22:24 ` Arnaud Spiwack 0 siblings, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 20:54 UTC (permalink / raw) To: Arnaud Spiwack; +Cc: caml-list On Thu, 2007-10-04 at 20:17 +0200, Arnaud Spiwack wrote: > > That would be wonderful if they did work... Unfortunately to my > knowledge, a software is a mere collection of bugs, glued together with > a couple of features. Or perhaps I'm being a little optimistic here :p . Lol! The one I hear is that a program is defined to be the tracks left by thousands of bugs. In the case of Ocaml, we might say that when many messages of the form: "This expression has type SquarePeg but is here used with type RoundHole" have been fixed by sandpapering off the edges of those pegs .. the program is the residual sawdust that remains on the floor after thousands of curses. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 20:54 ` skaller @ 2007-10-04 22:24 ` Arnaud Spiwack 0 siblings, 0 replies; 41+ messages in thread From: Arnaud Spiwack @ 2007-10-04 22:24 UTC (permalink / raw) To: caml-list > In the case of Ocaml, we might say that when many messages > of the form: "This expression has type SquarePeg but is here > used with type RoundHole" have been fixed by sandpapering > off the edges of those pegs .. the program is the residual sawdust > that remains on the floor after thousands of curses. > ^_^ You might really be interested in toying around with interactive systems. I would probably advise Adga2 ( http://appserv.cs.chalmers.se/users/ulfn/wiki/agda.php ) or Epigram 1 ( http://www.e-pig.org/ ). Interactive programming tends to save quite a few weird error messages. The type systems of these are of the sort we were discussing on this thread. Arnaud Spiwack ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 15:29 ` Andrej Bauer 2007-10-04 16:25 ` skaller @ 2007-10-04 16:37 ` skaller 2007-10-04 18:59 ` Christophe Raffalli 1 sibling, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 16:37 UTC (permalink / raw) To: Andrej.Bauer; +Cc: caml-list On Thu, 2007-10-04 at 17:29 +0200, Andrej Bauer wrote: > It is very easy to come up with preconditions that are computationally > unverifiable. [] > Or to give you a much more simplistic example: > > fun find_zero (f: int -> int where not (forall n:int, f(n) != 0)) { > int i = 0; > while (f(i) != 0) { i++; } > return i; > } > > How will you verify the precondition on f at runtime? In this case I > would expect the compiler to list all uses of find_zero applied to > functions which are not known not have a zero. Let the human worry. One 'solution' is a timeout. However I would apply the timeout to the actual find_zero function, not the pre-condition. The 'convex' example is better, because the pre-condition is not so obviously closely coupled to the calculation. Also, the result of a calculation is likely to be simply *wrong*. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 16:37 ` skaller @ 2007-10-04 18:59 ` Christophe Raffalli 0 siblings, 0 replies; 41+ messages in thread From: Christophe Raffalli @ 2007-10-04 18:59 UTC (permalink / raw) To: skaller; +Cc: Andrej.Bauer, caml-list [-- Attachment #1.1: Type: text/plain, Size: 1641 bytes --] > On Thu, 2007-10-04 at 17:29 +0200, Andrej Bauer wrote: > > >> It is very easy to come up with preconditions that are computationally >> unverifiable. >> > [] > >> Or to give you a much more simplistic example: >> >> fun find_zero (f: int -> int where not (forall n:int, f(n) != 0)) { >> int i = 0; >> while (f(i) != 0) { i++; } >> return i; >> } >> >> How will you verify the precondition on f at runtime? In this case I >> would expect the compiler to list all uses of find_zero applied to >> functions which are not known not have a zero. Let the human worry. >> > > What's the problem ? If you program with the above function and apply it to a function f, this means you know f will reach zero (otherwise your program will loop). But if you know it, this should mean that you can prove it from the definition of f ? So the only reason to have today programming language that gives not enough safety is because the cost of the formal proof is still to big (by cost, I mean cost to write proof, but also the cost of learning how to write proof ...) -- Christophe Raffalli Universite de Savoie Batiment Le Chablais, bureau 21 73376 Le Bourget-du-Lac Cedex tel: (33) 4 79 75 81 03 fax: (33) 4 79 75 87 42 mail: Christophe.Raffalli@univ-savoie.fr www: http://www.lama.univ-savoie.fr/~RAFFALLI --------------------------------------------- IMPORTANT: this mail is signed using PGP/MIME At least Enigmail/Mozilla, mutt or evolution can check this signature. The public key is stored on www.keyserver.net --------------------------------------------- [-- Attachment #1.2: Christophe.Raffalli.vcf --] [-- Type: text/x-vcard, Size: 310 bytes --] begin:vcard fn:Christophe Raffalli n:Raffalli;Christophe org:LAMA (UMR 5127) email;internet:christophe.raffalli@univ-savoie.fr title;quoted-printable:Ma=C3=AEtre de conf=C3=A9rences tel;work:+33 4 79 75 81 03 note:http://www.lama.univ-savoie.fr/~raffalli x-mozilla-html:TRUE version:2.1 end:vcard [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 249 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 8:56 ` Arnaud Spiwack 2007-10-04 14:49 ` skaller @ 2007-10-04 15:04 ` Andrej Bauer 2007-10-04 15:57 ` Christophe Raffalli 2007-10-04 16:03 ` skaller 1 sibling, 2 replies; 41+ messages in thread From: Andrej Bauer @ 2007-10-04 15:04 UTC (permalink / raw) To: caml-list; +Cc: Arnaud Spiwack I too have a compulsive obsession to talk about logic, so here is my contribution. Logic is about details. It is only to be expected that in a willy-waving competition on a mailing list like ours everyone will get something wrong about such a tricky thing as Goedel's theorems (me included). For example: Christophe Raffalli: > - first if a type system does not contain arithmetic nothing can be said > (this implies ML), but in this case, the meaning of complete needs to be clarified. > Indeed, there are complete type system ... In logic complete usually means: for every sentence A the system proves A or it proves not A. This has nothing to do with being able to interpret arithmetic. We can define completeness without reference to arithmetic. (Presumably, a type system is complete if for every (closed) type A, A is inhabited or A -> void is inhabited. At least this would be the reading of completeness under propositions-as-types.) Christophe Raffalli: > - The 1st incompleteness theorem states that no theory containing > arithmetic is complete. No _sound_ theory interpreting arithmetic is complete. Arnaud Spiwack wrote: > Anyway, back to Mr. Gödel and his theorem. What he stated indeed is that > truth and provability never coincide (provided we're talking of > something at least as expressive as arithmetic). Goedel's theorems say nothing directly about truth. This is a common misconception. Skaller started the discussion with a rerefence to Geodel, which he did not attempt to use in a technically correct way. I think it would be beneficial for this discussion to move away from explicit references to Goedel. We seem to be talking about two things: a) Expressiveness of a type system vs. decidability of type-checking. The main point is that the more expressive the type system the harder it is to check types. b) Safety guarantees for well-typed programs A typical safety guarantee is expressed with the Preservation Lemma ("Types are preserved during evaluation") and Progress Lemma ("A typed program is either a value or has a next evaluation step"). Together these two imply, e.g., that there won't be a segmentation fault. I think to some extent (b) is what skaller calls "soundness". If I read skaller correctly, he made three points (please correct me if not): 1) The safety properties of well-typed programs in C are none, but Ocaml is not much better either, since it just pretends that exceptions are safe. Therefore, to at least some degree the slogan "the Ocaml type system guarantees safety" is not entirely and honestly true. 2) Morally inferior languages such as C and Python are popular because people are not willing to write programs with their hands tied to their backs by a typing system. 3) Skaller would rather have poor safety guarantees than an inexpressive type system that ties his hands. Goedel is dragged in only because his theorems tell us that the perfect world does not exist, i.e., we cannot have decidable type checking of a very expressive type system which also has sane safety properties. Leaving Goedel aside for a moment, we can ask what a good practical combination of expressiveness and safety would be. We have to give up at least one of the three desired properties (expressiveness, decidability of type checking, safety). Various languages make various choices, as was already mentioned in this thread. Let me just say that the choice made by C, i.e., to give up both expressiveness and safety in return for easy type-checking is not as crazy as it may sound (imagine it's 1970, your computer has 4kb of memory, everybody around you thinks of types as hints to compilers about how many bytes of storage a variable will take, and Martin-Lof is just an obscure Scandinavian mathematician and/or philosopher that real programmers never heard of). It seems to me that the evolution of theory-backed languages such as ML and Haskell is reaching a point where people are willing to give up decidability of type-checking (Haskell has done it). Skaller seems to think that the only option is to give up safety, as well, with which I disagree. We need _controlled_ unsafety. My position is this: i) Insist on good safety properties. If a program compiles without any "ifs" and "buts", then it is safe (whatever that means). It the compiler thinks the program might be unsafe it should try to compile anyhow, and tell us why precisely it thinks it might be unsafe. ii) Give programmers very expressive type systems so that they can write things like div : int * {x : int | not (x = 0)} -> int and much more. iii) Of course, by combining i) and ii) we must then give up decidability of type-checking. We can compensate for that loss by _making compilers more interactive_. The current model, where a compiler either succeeds on its own or fails completely, is not going to take us much further. People from the automated theorem proving community learnt a while ago that the interaction between the human and the computer is the way to go. A compiler should be able to take hints on how to check types. The result of compilation should be one of: - everything is ok - the program contains a grave typing error which prevents the compiler from emitting sane code, compilation is aborted - the compiler generates sane code but also emits a list of assertions which need to be checked (by humans or otherwise) in order to guarantee safety If we had compilers like that, they would greatly encourage good programming practices. You can read the above as my manifesto, if you wish. Best regards, Andrej ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 15:04 ` Andrej Bauer @ 2007-10-04 15:57 ` Christophe Raffalli 2007-10-04 16:03 ` skaller 1 sibling, 0 replies; 41+ messages in thread From: Christophe Raffalli @ 2007-10-04 15:57 UTC (permalink / raw) To: Andrej.Bauer; +Cc: caml-list [-- Attachment #1.1: Type: text/plain, Size: 3303 bytes --] Andrej Bauer a écrit : > I too have a compulsive obsession to talk about logic, so here is my > contribution. > > Logic is about details. It is only to be expected that in a > willy-waving competition on a mailing list like ours everyone will get > something wrong about such a tricky thing as Goedel's theorems (me > included). For example: > > Christophe Raffalli: >> - first if a type system does not contain arithmetic nothing can be said >> (this implies ML), but in this case, the meaning of complete needs to >> be clarified. >> Indeed, there are complete type system ... > In logic complete usually means: for every sentence A the system > proves A or it proves not A. This has nothing to do with being able to > interpret arithmetic. We can define completeness without reference to > arithmetic. Sorry, I see now that I was not clear enough : Complete (at least in french) has many meanings, the one you said and the fact that something true in every model is provable (which make a lot of meaning depending to the models you are considering). The two meanings are unrelated, because arithmetics is complete as is any first order theory (this is Gödel Completeness theorem for predicate logic), but incomplete because there are formula A such that neither A nor not A are provable. This is quite confusing. But in both case complete means "there are enough rules/axioms in the system to do what I want". You are just making the "what I want" more or less strong. For type systems, if you replace proving by inhabited, they are usually incomplete, but then, you can look for completeness relative to some model (like realizability) ... and the answer is yes in some cases. This is generally a good idea to search for a set of models large enough for your type system to be complete ... because sometime you realize that you forgot some usefull typing rules in your type system. > > (Presumably, a type system is complete if for every (closed) type A, > A is inhabited or A -> void is inhabited. At least this would be the > reading of completeness under propositions-as-types.) > > Christophe Raffalli: >> - The 1st incompleteness theorem states that no theory containing >> arithmetic is complete. > > No _sound_ theory interpreting arithmetic is complete. Ok, this was implicit. > > Arnaud Spiwack wrote: >> Anyway, back to Mr. Gödel and his theorem. What he stated indeed is >> that truth and provability never coincide (provided we're talking of >> something at least as expressive as arithmetic). This is Tarski's result .... (actually Tarski proved that truth can not even be defined by a formula of arithmetic, which imply that provability and truth do not coincide because provable formula are definable). -- Christophe Raffalli Universite de Savoie Batiment Le Chablais, bureau 21 73376 Le Bourget-du-Lac Cedex tel: (33) 4 79 75 81 03 fax: (33) 4 79 75 87 42 mail: Christophe.Raffalli@univ-savoie.fr www: http://www.lama.univ-savoie.fr/~RAFFALLI --------------------------------------------- IMPORTANT: this mail is signed using PGP/MIME At least Enigmail/Mozilla, mutt or evolution can check this signature. The public key is stored on www.keyserver.net --------------------------------------------- [-- Attachment #1.2: Christophe.Raffalli.vcf --] [-- Type: text/x-vcard, Size: 310 bytes --] begin:vcard fn:Christophe Raffalli n:Raffalli;Christophe org:LAMA (UMR 5127) email;internet:christophe.raffalli@univ-savoie.fr title;quoted-printable:Ma=C3=AEtre de conf=C3=A9rences tel;work:+33 4 79 75 81 03 note:http://www.lama.univ-savoie.fr/~raffalli x-mozilla-html:TRUE version:2.1 end:vcard [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 249 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 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 1 sibling, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 16:03 UTC (permalink / raw) To: Andrej.Bauer; +Cc: caml-list On Thu, 2007-10-04 at 17:04 +0200, Andrej Bauer wrote: [] Thanks. I think this is a very good interpretation of my intent. > 3) Skaller would rather have poor safety guarantees than an inexpressive > type system that ties his hands. That's not quite right: it isn't that typing prevents me writing my programs (it does sometimes, but usually that indicates a design fault). It's more like the lack of expressiveness prevents me writing down the invariants and so forth I actually want to. I have to keep them in my head, or write them as comments where they're not sanity checked. In Felix for example the standard library contains this: // additive symmetric group typeclass FloatAddgrp[t] { inherit Eq[t]; virtual fun zero: 1 -> t; virtual fun add: t * t -> t; virtual fun neg: t -> t; virtual fun sub(x:t,y:t):t => add (x,neg y); reduce id (x:t): x+zero() => x; reduce id (x:t): zero()+x => x; reduce inv(x:t): x-x => zero(); reduce inv(x:t): - (-x) => x; axiom sym (x:t,y:t): x+y == y+x; } typeclass Addgrp[t] { inherit FloatAddgrp[t]; axiom assoc (x:t,y:t,z:t): (x+y)+z == x+(y+z); reduce inv(x:t,y:t): x+y-y => x; } and here I can encode a LOT more information about the type T the typeclass describes than Haskell allows. Furthermore, the 'reduce' axioms have operational semantics (Felix really does apply these reductions) and the axioms can be tested by using a statement like check(1,2); which is how I discovered floating point arithmetic isn't associative -- an actual regression test failed. What is more Felix allows a 'lemma' which is an axiom which is made into a proof goal in Why format for submission to a theorem prover. This notation is weak, and the Felix compiler cannot really prove much with it: for example it does not check instances of typeclasses meet their obligations. But at least the semantics are encoded in the language and type checked, I can make reasoned arguments based on the stated semantics, and there is some hope someone will come along and implement some actual proof procedures and/or optimisations at a later date. [I really have proven one trivial lemma using both Ergo and Simplify.] Vincent Aravantinos made the important point: "If you allow everything (such as the "type expressive" C you are envisaging), the programmer will be tempted to use this "everything" whereas he could achieve the same with a "bounded" language." and the admission of semantics into the system is the starting point for allowing one to at least state some of those bounds (even if there is little or no enforcement the bounds are formalised). > Goedel is dragged in only because his theorems tell us that the perfect > world does not exist, i.e., we cannot have decidable type checking of a > very expressive type system which also has sane safety properties. Ooops, I am sprung! > Skaller seems to > think that the only option is to give up safety, as well, with which I > disagree. We need _controlled_ unsafety. Actually I HOPED someone smart enough would dare make such a proposal. I think I alluded to this idea in the claims that adding unsound typing to the existing Ocaml type system such as non-zero integers will not actually compromise safety, but rather enhance it. However I just do not understand how to say 'It is safe up to this point, and risky from there on'. I have no mental concept of 'delimited unsoundness'. In an analogous context I had no idea how to mix side-effecting and functional code in a delimited way until I saw how Haskell does it with Monads. > My position is this: > > i) Insist on good safety properties. If a program compiles without any > "ifs" and "buts", then it is safe (whatever that means). It the compiler > thinks the program might be unsafe it should try to compile anyhow, and > tell us why precisely it thinks it might be unsafe. Of course, all pragmatic compilers offer switches to control this kind of thing. > iii) Of course, by combining i) and ii) we must then give up > decidability of type-checking. We can compensate for that loss by > _making compilers more interactive_. The current model, where a compiler > either succeeds on its own or fails completely, is not going to take us > much further. People from the automated theorem proving community learnt > a while ago that the interaction between the human and the computer is > the way to go. Ah. > A compiler should be able to take hints on how to check types. The > result of compilation should be one of: > > - everything is ok > > - the program contains a grave typing error which prevents > the compiler from emitting sane code, compilation is aborted > > - the compiler generates sane code but also emits a list of assertions > which need to be checked (by humans or otherwise) in order to > guarantee safety > > If we had compilers like that, they would greatly encourage good > programming practices. > > You can read the above as my manifesto, if you wish. This is quite good from an industrial viewpoint. The list of assertions can be reduced by more work in selective areas as a complement to testing. This gives managers control over risk. It seems a consequence of this manifesto is that the asserting of the assertions, if not their proofs, need to be encoded into the program in an effort to reduce the size of the output list. A difficulty here is saying the assertions in a comprehensible way which is well coupled to the original code. As you said previously, this probably requires an interactive system. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 16:03 ` skaller @ 2007-10-04 20:02 ` Ken Rose 2007-10-04 21:00 ` skaller 0 siblings, 1 reply; 41+ messages in thread From: Ken Rose @ 2007-10-04 20:02 UTC (permalink / raw) To: skaller; +Cc: caml-list skaller wrote: > It seems a consequence of this manifesto is that the asserting > of the assertions, if not their proofs, need to be encoded > into the program in an effort to reduce the size of the output > list. > > A difficulty here is saying the assertions in a comprehensible > way which is well coupled to the original code. As you said > previously, this probably requires an interactive system. > > I think that in an industrial system, the assertions are going to have to travel with the code. I can't imagine that a system that needs a particular, highly trained programmer (the one who wrote the thing) to cajole the compiler into generating code will ever be satisfactory to any business that writes code. - ken ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 20:02 ` Ken Rose @ 2007-10-04 21:00 ` skaller 0 siblings, 0 replies; 41+ messages in thread From: skaller @ 2007-10-04 21:00 UTC (permalink / raw) To: Ken Rose; +Cc: caml-list On Thu, 2007-10-04 at 13:02 -0700, Ken Rose wrote: > skaller wrote: > > It seems a consequence of this manifesto is that the asserting > > of the assertions, if not their proofs, need to be encoded > > into the program in an effort to reduce the size of the output > > list. > > > > A difficulty here is saying the assertions in a comprehensible > > way which is well coupled to the original code. As you said > > previously, this probably requires an interactive system. > > > > > I think that in an industrial system, the assertions are going to have > to travel with the code. I can't imagine that a system that needs a > particular, highly trained programmer (the one who wrote the thing) to > cajole the compiler into generating code will ever be satisfactory to > any business that writes code. There is a such a system, I can't remember its name. The proofs and types etc do travel with the code, but the 'language' is designed with holes to fill in interactively, and the compiler fills them out partially then prompts for the balance. After supply, more holes are filled in by the same process. So for export, you get a complete linear representation of the conventional kind but you use a GUI to develop it. Perhaps someone can provide a link (it's quite well known very advanced category theory based system). -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 22:50 ` Unsoundness is essential skaller ` (2 preceding siblings ...) 2007-10-03 23:28 ` Joshua D. Guttman @ 2007-10-04 15:31 ` Lukasz Stafiniak 2007-10-04 17:56 ` rossberg 4 siblings, 0 replies; 41+ messages in thread From: Lukasz Stafiniak @ 2007-10-04 15:31 UTC (permalink / raw) To: skaller; +Cc: caml-list A "sound program refuter" will not reject correct programs. On 10/4/07, skaller <skaller@users.sourceforge.net> wrote: > > To be bold I propose type theorists have got it totally wrong. > > I want an unsound type system! It much better than the useless > but 'sound' type system of Python, in which the type inference > engine decides all values have type Object and proves > in vacuuo that all programs are type-safe, only to do the > dependent type checks at run time anyhow -- a cheat known > as dynamic typing. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-03 22:50 ` Unsoundness is essential skaller ` (3 preceding siblings ...) 2007-10-04 15:31 ` Lukasz Stafiniak @ 2007-10-04 17:56 ` rossberg 2007-10-04 19:56 ` skaller 4 siblings, 1 reply; 41+ messages in thread From: rossberg @ 2007-10-04 17:56 UTC (permalink / raw) To: skaller; +Cc: caml-list skaller wrote: > > All advanced programming languages have unsound type systems > of necessity. Some falsely claim soundness by denying the > expression of certain type information (eg array bounds > or the type of integers excluding zero). No. Soundness is the absence of /untrapped/ errors. Exceptions are /trapped/ errors. Huge difference, esp with respect to safety and security. - Andreas ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 17:56 ` rossberg @ 2007-10-04 19:56 ` skaller 2007-10-04 21:07 ` rossberg 0 siblings, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 19:56 UTC (permalink / raw) To: rossberg; +Cc: caml-list On Thu, 2007-10-04 at 19:56 +0200, rossberg@ps.uni-sb.de wrote: > skaller wrote: > > > > All advanced programming languages have unsound type systems > > of necessity. Some falsely claim soundness by denying the > > expression of certain type information (eg array bounds > > or the type of integers excluding zero). > > No. Soundness is the absence of /untrapped/ errors. Fair .. > Exceptions are /trapped/ errors. I chose not to accept that definition. I use instead "trapped at compile time", meaning "in advance of running the program". Otherwise you could say dynamically typed languages were strongly typed and sound. I'm not saying that it is a bad thing to emit code to generate diagnostics at run time, if you can't prove safety at compile time .. I AM saying that doing that means the type system is unsound, because by type system I mean "static type checking". The point is that static checks are hopefully rigorous: what ever properties they ensure they ensure them for certain, once and for all time. Whereas dynamic checks prove only, in some cases, that there is a bug and thus you have to actually test the program with good coverage, and even then you learn little UNLESS there is a bug :) Also note, specified exceptions are not suitable traps: this is a conformance issue and not really related, but it is worth noting that if a catchable exception is specified, the condition that caused it to be raised isn't necessarily an error: try: x = "Bad" +42 except: print "Python WILL print this" This code is perfectly well defined and contains no errors, not even a type error. Adding a string to an integer raises TypeError in Python, and this is mandatory, so this behaviour is well defined and can be used as a programming technique (and it is!), there is no 'trapped' error here. C/C++ does this right: if a program is 'ill-formed' then a diagnostic must be issued. Throwing an exception silently is NOT allowed. [C/C++ doesn't mandate diagnostics always because some are too hard to detect] -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 19:56 ` skaller @ 2007-10-04 21:07 ` rossberg 2007-10-04 22:23 ` skaller 0 siblings, 1 reply; 41+ messages in thread From: rossberg @ 2007-10-04 21:07 UTC (permalink / raw) To: skaller; +Cc: caml-list skaller wrote: > >> Exceptions are /trapped/ errors. > > I chose not to accept that definition. I use instead > "trapped at compile time", meaning "in advance of running > the program". As a definition for what? > Otherwise you could say dynamically typed languages were > strongly typed and sound. In fact, technically, they are. People have used the term "unityped" for it. > C/C++ does this right: if a program is 'ill-formed' then > a diagnostic must be issued. Throwing an exception silently > is NOT allowed. [C/C++ doesn't mandate diagnostics always because > some are too hard to detect] This paragraph sounds like a contradiction in itself. More importantly, an OCaml program performing div 0 isn't "ill-formed", it has a perfectly well-defined, safe semantics (in precisely the same way as adding a string in Python). See the library docs. - Andreas ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Caml-list] Unsoundness is essential 2007-10-04 21:07 ` rossberg @ 2007-10-04 22:23 ` skaller 2007-10-05 2:48 ` Bárður Árantsson 0 siblings, 1 reply; 41+ messages in thread From: skaller @ 2007-10-04 22:23 UTC (permalink / raw) To: rossberg; +Cc: caml-list On Thu, 2007-10-04 at 23:07 +0200, rossberg@ps.uni-sb.de wrote: > skaller wrote: > > > >> Exceptions are /trapped/ errors. > > > > I chose not to accept that definition. I use instead > > "trapped at compile time", meaning "in advance of running > > the program". > > As a definition for what? What trapped means. > > Otherwise you could say dynamically typed languages were > > strongly typed and sound. > > In fact, technically, they are. People have used the term "unityped" for it. That isn't what I meant at all. Python is statically unityped, but dynamically it has integers, reals, strings, etc. Type errors in Python are not 'trapped' .. they're impossible. > > C/C++ does this right: if a program is 'ill-formed' then > > a diagnostic must be issued. Throwing an exception silently > > is NOT allowed. [C/C++ doesn't mandate diagnostics always because > > some are too hard to detect] > > This paragraph sounds like a contradiction in itself. Yes, but it isn't. If the specification was to throw a catchable exception, then that would be a requirement on implementation which would permit programmers to divide by zero deliberately. In that case, a divide by zero error is impossible to detect because it can't be distinguished from the legitimate division by zero for the purpose of raising an exception. > More importantly, an OCaml program performing div 0 isn't "ill-formed", it > has a perfectly well-defined, safe semantics (in precisely the same way as > adding a string in Python). See the library docs. I didn't claim otherwise: I claim it is a very bad idea to permit a program to do obvious bullshit like divide by zero (for integers I mean). Note I'm NOT saying Ocaml *implementation* shouldn't raise an exception, just that the language specification should not require it do so. The difference is in one case the operation is semantically well defined and thus definitely not detectable as an error, whereas in the other it is not defined, and so is unequivocably an error. Oh well this was fun but I'm off interstate without a computer for a week.. hope my Airbus doesn't divide any empty lists by zero .. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: Unsoundness is essential 2007-10-04 22:23 ` skaller @ 2007-10-05 2:48 ` Bárður Árantsson 0 siblings, 0 replies; 41+ messages in thread From: Bárður Árantsson @ 2007-10-05 2:48 UTC (permalink / raw) To: caml-list skaller wrote: > On Thu, 2007-10-04 at 23:07 +0200, rossberg@ps.uni-sb.de wrote: >> skaller wrote: >>>> Exceptions are /trapped/ errors. >>> I chose not to accept that definition. I use instead >>> "trapped at compile time", meaning "in advance of running >>> the program". >> As a definition for what? > > What trapped means. > >>> Otherwise you could say dynamically typed languages were >>> strongly typed and sound. >> In fact, technically, they are. People have used the term "unityped" for it. > > That isn't what I meant at all. Python is statically unityped, but > dynamically it has integers, reals, strings, etc. Type errors > in Python are not 'trapped' .. they're impossible. > $ python Python 2.5.1 (r251:54863, Oct 1 2007, 21:44:24) [GCC 4.1.2 (Gentoo 4.1.2)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 1 + "a" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'int' and 'str' -- Bardur Arantsson <bardurREMOVE@THISscientician.net> - I may not have morals, but I do have standards. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: Locally-polymorphic exceptions [was: folding over a file] 2007-10-03 11:27 ` kirillkh 2007-10-03 11:48 ` [Caml-list] " Daniel de Rauglaudre 2007-10-03 20:39 ` Christophe Raffalli @ 2007-10-04 2:16 ` oleg 2 siblings, 0 replies; 41+ messages in thread From: oleg @ 2007-10-04 2:16 UTC (permalink / raw) To: kirillkh; +Cc: caml-list > Could you be more specific regarding the continuations' performance impact? > Would it matter in practice? Would you recommend using this function in a > general-purpose library instead of the imperative-style implementation that > was suggested? For use in practice (including ocamlopt -- the case delimcc does not yet support: I should really fix that) one should probably `inline' the implementation of abort into the code of fold_file. The result will _literally_ be the following: exception Done (* could be hidden in a module *) let fold_file (file: in_channel) (read_func: in_channel->'a) (elem_func: 'a->'b->'b) (seed: 'b) = let result = ref None in let rec loop prev_val = let input = try read_func file with End_of_file -> result := Some prev_val; raise Done in let combined_val = elem_func input prev_val in loop combined_val in try loop seed with Done -> (match !result with Some x -> x | _ -> failwith "impossible!") ;; (* 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 *) It should be noted the differences from the previous imperative solutions: the reference cell result is written only once and read only once in the whole folding -- namely, at the very end. The reference cell is written to, and then immediately read from. The bulk of the iteration is functional and tail recursive. The use of mutable cell is the trick behind typing of multi-prompt delimited continuations. One may even say that if a type system supports reference cells, it shall support multi-prompt delimited continuations -- *and vice versa*. > Also, is there a good manual on delimited continuations for a beginner with > minimum of external references? Perhaps the most comprehensive and self-contained paper on delimited continuations is A static simulation of dynamic delimited control by Chung-chieh Shan http://www.cs.rutgers.edu/~ccshan/recur/recur-hosc-final.pdf I have heard some people have found the introduction section of http://okmij.org/ftp/Computation/Continuations.html#context-OS helpful. Please note Christopher Strachey's quote on the above page. It was said back in 1974! Here's another quote from the same Strachey and Wadsworth's paper: Those of us who have worked with continuations for some time have soon learned to think of them as natural and in fact often simpler than the earlier methods. Christopher Strachey and Christopher P. Wadsworth, 1974. ^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2007-10-05 2:49 UTC | newest] Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-10-03 8:35 Locally-polymorphic exceptions [was: folding over a file] oleg 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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox