From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Delivered-To: caml-list@yquem.inria.fr Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by yquem.inria.fr (Postfix) with ESMTP id D183CBB91 for ; Fri, 28 Jan 2005 16:48:36 +0100 (CET) Received: from pauillac.inria.fr (pauillac.inria.fr [128.93.11.35]) by nez-perce.inria.fr (8.13.0/8.13.0) with ESMTP id j0SFmZaT011754 for ; Fri, 28 Jan 2005 16:48:36 +0100 Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id QAA08774 for ; Fri, 28 Jan 2005 16:48:35 +0100 (MET) Received: from smtp3.adl2.internode.on.net (smtp3.adl2.internode.on.net [203.16.214.203]) by concorde.inria.fr (8.13.0/8.13.0) with ESMTP id j0SFmXGE029358 for ; Fri, 28 Jan 2005 16:48:34 +0100 Received: from [192.168.1.200] (ppp205-248.lns1.syd3.internode.on.net [203.122.205.248]) by smtp3.adl2.internode.on.net (8.12.9/8.12.9) with ESMTP id j0SFmKc2073813; Sat, 29 Jan 2005 02:18:25 +1030 (CST) Subject: Re: [Caml-list] Re: '_a From: skaller Reply-To: skaller@users.sourceforge.net To: Keith Wansbrough Cc: Stefan Monnier , caml-list In-Reply-To: References: Content-Type: text/plain Message-Id: <1106927299.23562.187.camel@pelican.wigram> Mime-Version: 1.0 X-Mailer: Ximian Evolution 1.2.2 (1.2.2-4) Date: 29 Jan 2005 02:48:20 +1100 Content-Transfer-Encoding: 7bit X-Miltered: at nez-perce with ID 41FA5ED4.000 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Miltered: at concorde with ID 41FA5ED1.001 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Spam: no; 0.00; caml-list:01 sourceforge:01 wrote:01 umontreal:01 recursion:01 failwith:01 terminate:01 ocaml:01 haskell:01 ocaml:01 abstraction:01 haskell:01 monads:01 closures:01 abstraction:01 X-Spam-Checker-Version: SpamAssassin 3.0.0 (2004-09-13) on yquem.inria.fr X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=disabled version=3.0.0 X-Spam-Level: On Sat, 2005-01-29 at 01:46, Keith Wansbrough wrote: > Stefan Monnier writes: > > > > (b) the codomain is mis-specified, we actually have > > > List.hd: 'a list -> Some 'a > > > > Funny, I always assumed that the domain of List.hd was "'a list - []". > > Yes, indeed. Were List.hd of type 'a list -> 'a option, we'd be stuck > if we ever wanted actually to _use_ the value: any function that > attempted to extract it (say f : 'a option -> 'a) would have to have a > similar type (f : 'a option -> 'a option). Of course! That's what destructors are for. Ultimately, there's no choice, no matter how you factor it you cannot have a List.hd function returning a non sum: destructors are the *only* way to analyse sums. The data summation *must* be dualised by a destructor to convert that data into control branches. Note that List.hd actually does that .. but one of the control paths is implicit (the one carried by the exception). > The only way out of this mess is to add a monad. That isn't the only way. I have a fairly large project that only throw an exception in *one* essential place (to get out of a really deep complex recursion). With one exception -- i do use 'monadic' failwith () like functions to terminate when I detect an error (and I do use that a lot), these are all caught at the top level (and they're not allowed to be caught anywhere else). Otherwise .. I find the 'pain' of using destructors everywhere preferable to throwing exceptions -- the additional complexity of the control paths is a small price to pay for their localisation. Meaning -- I sometimes have trouble holding enough of a picture in my head to understand my code, but with exceptions I'm completely lost because half the code isn't even visible :) > OCaml already has > one: return is implicit, bind is called ";", and the monad operations > include "raise" and "try ... with ...". Indeed, but that isn't necessarily a good monad for all purposes (otherwise Haskell would be Ocaml and wouldn't have any typeclasses .. LOL :) In particular, raise is very nasty -- I can't say this very well, but 'the monad is too global'. It's way too powerful -- and thus too hard to reason about. I think this is because it crosses abstraction boundaries. You can't predict what a function will throw from its interface, so you basically have lost control of your program. As I understand it, Haskell style monads provide better localisation (is that right?) The problem with using destructors left, right, and centre, is that you need heaps of extremely localised code to handle all the cases. However going from that to total globality is no solution. (In the first case the error handling is too tighly coupled to the error detection, and in the second too loosely coupled). Exception specs try to relieve this but they don't work. To me the solution appears to require some kind of 'static exceptions'. Felix uses a non-local goto. This is definitely better for some purpose than dynamic EH, since it ensures every 'throw' has a matching 'catch'. The goto can be wrapped in a closure and passed explicitly anywhere inside the closures abstraction, allowing both static and dynamic control path to be constructed: either way the path is either manifest (by locality) or explicit (by argument passing). However this solution is not modular. EG: you can provide a handler for division by zero, by there's no guarrantee the client you pass it to actually calls it for the correct error .. :) Monads provide better modularity? -- John Skaller, mailto:skaller@users.sf.net voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net