Re: [Haskell-cafe] embedding prolog in haskell.
On 18-Aug-2005, Keean Schupke [EMAIL PROTECTED] wrote: I was wondering if anyone has any comments on my implementation of unify? For example can the algorithm be simplified from my nieve attempt? Most importantly is it correct? type Subst = [(Vname,Term)] data Term = Func Fname [Term] | Var Vname deriving (Eq,Show) type Fname = String data Vname = Name String | Auto Integer deriving (Eq,Show) unify :: Subst - (Term,Term) - [Subst] unify s (t,u) | t == u = [s] You should delete the line above. It's not needed and could cause serious efficiency problems. With that line present, unifying two lists of length N which differ only in the last element would take time proportional to N squared, but without it, the time should be linear in N. unify s (Var x,t) = [(x,t):s] -- no occurs check unify s (t,Var x) = [(x,t):s] -- no occurs check These are not right; you need to look up the variable x in the substitution s, and if it is already bound, then you need to unify what it is bound to with the term t. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Updating the Haskell Standard
On 20-Jul-2005, David Barton [EMAIL PROTECTED] wrote: I can contribute some experience from commercial standardization efforts. ANSI, IEEE, and ISO standards require re-ballotting every five years, otherwise the standards lapse. Reballotting may or may not be accompanied by changes in the standard; for a standard as complex as a language, new versions at least every five years seems to be fairly common with newer standards [...] Five years is what the general industry seems to have settled on as a good average, but it may or may not apply here; the circumstances are different. ANSI/ISO programming language standards typically undergo major updates every 10 years or so: Fortran 66, 77, 95, 2003; COBOL 68, 74, 85, 2002; Ada 83, 95, 2005; C 89, 99; C++ 98, 200x (for some x = 5). (ANSI C has not changed in newer standardization ballots as far as I know). A major new update to the ANSI/ISO C standard was issued in 1999. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ghc 6.4 import problem
On 31-May-2005, Daniel Fischer [EMAIL PROTECTED] wrote: Am Freitag, 27. Mai 2005 02:06 schrieb Shiqi Cao: I tried to port some code from ghc 6.2 to ghc 6.4, but I got the following error PrelExts.lhs:41:25: Ambiguous occurrence `map' It could refer to either `GHC.Base.map', imported from Data.List at PrelExts.lhs:11:0-15 or `Data.Set.map', imported from Data.Set at PrelExts.lhs:10:0-14 The following is the first part of the code module PrelExts where import Data.FiniteMap import Data.Set import Data.List import IO There is no problem under ghc 6.2. What should I do? ... To solve your problem, use import controls, for example import Data.Set hiding (map) import qualified Data.Set as Set will do fine. That code only compiles with ghc 6.4, and won't compile with ghc 6.2: you'll get an error for the hiding (map) part, because in 6.2 Data.Set does not contain a map function. If you want code that compiles with both 6.2 and 6.4 and does not give any warnings with ghc -Wall, then I think you'll need to use qualified imports, i.e. just the second line above. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] hugs segmentation fault
On 29-Oct-2004, Ben Rudiak-Gould [EMAIL PROTECTED] wrote: Jon Fairbairn wrote: On 2004-10-29 at 00:03BST Ben Rudiak-Gould wrote: Not much better, though: in my experience this particular exception leaves ghci in a very peculiar state, and it's usually necessary to quit and restart it before it will work again. I don't think I've seen such a problem (maybe I so rarely make that type of mistake?;-). What version? What are the symptoms of this not working of which you speak? It seems OK in ghci 6.2.1 We ran into a related problem recently. I think the problem may only show up on Windows, not on Linux. The problem is that when a loop occurs, ghc's garbage collection detects that the standard I/O handles for stdin/stdout/stderr can no longer be referenced and finalizes them, *before* detecting the loop and throwing an exception. Subsequent code may then attempt to use these already-finalized standard I/O handles. A possible work-around is to create stable pointers to those handles. But I'm not sure whether this is the same problem that you are experiencing. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: OCaml list sees abysmal Language Shootout results
On 08-Oct-2004, Andre Pang [EMAIL PROTECTED] wrote: I believe that Marcin wishes to prove the same point that I want to: namely, Clean encourages use of strictness by making it easier to use (via language annotations). At the risk of sounding ignorant and arrogant, I think the Haskell community in general does not understand the importance of syntactic sugar to make such tasks easier. I think the Haskell community understands well the importance of syntactic sugar; witness the use of syntactic sugar for monads, the `infix` operator syntax, the layout rules, etc. I think the Haskell community has just been a bit slower in understanding the importance of strictness :) But that seems to be gradually changing. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Optmiization of recursion
On 28-Sep-2004, John Goerzen [EMAIL PROTECTED] wrote: As I'm investigating Haskell, it's occured to me that most of the Haskell tutorials out there have omitted something that was quite prominent in the OCaml material I had read: making functions properly tail-recursive. The OCaml compiler was able to optimize tail-recursive functions such that they could be compiled using a loop. This would achieve two main benefits: performance due to not needing to allocate/deallocate stack frames, and the ability to work on very large lists since each recursive call did not consume extra stack space. So I have several questions about Haskell: 1. Do Haskell interpreters/compilers perform similar optimizations? Yes. However, laziness has a major effect on space usage and on the applicability and importance of tail call optimization. 4. Is a reference available documenting which Prelude/standard functions are properly tail-recursive (and thus suitable for very large lists) and which are not? No. But the source code is available... If analyzing the performance and space usage of your programs is important, then Haskell may not be the best choice of language. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] complete documentation like the one from Java or C++
On 10-Sep-2004, Cale Gibbard [EMAIL PROTECTED] wrote: Just in case it's not what you're referring to, http://www.haskell.org/ghc/docs/latest/html/libraries/index.html together with the Haskell report http://www.haskell.org/onlinereport/ generally does the trick for me. Occasionally, descriptions are left out when the name of the thing together with the type signature generally tells you what it does. (e.g. things like isEmptySet :: Set a - Bool are pretty obvious.) Sometimes descriptions are left out even when it is not obvious. For example, the documentation for Control.Monad.Fix http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control.Monad.Fix.html merely says The Fix monad. Inspired by [... reference to 40-page paper ...]., and it turns out that the module is only very loosely inspired by a few small parts of the cited paper. The module defines a class method mfix which is not documented and which does not appear to correspond with any class method in the cited paper. In this case, since the function is a class method, it is crucial to document the intended contract which users of the class method can assume and which implementors of the class method must satisfy. But this has not been done. The Control.Monad.Fix module also defines a function fix, and here things seem a little better, since there is a function fix mentioned in the paper (NOT in the paper's section on monads, but instead in a section titled computing with lattices). However, the fix function in the paper has a different type than the fix function in Control.Monad.Fix, and because of this the two cannot possibly have the same semantics. In the case of fix, you can at least look at the ghc library source code. But that doesn't work for class methods like mfix. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] cost of List.// for Ord types?
On 03-Sep-2004, David Roundy [EMAIL PROTECTED] wrote: I was wondering if the list diff operator \\ takes advantage of situations where the list data type is in class Ord, besides being in Eq. No, it cannot, at least not in the general case. The interface for \\ says that it only depends on the Eq class; calling Ord member functions would not have the right semantics. Basically, I'm wondering if I should avoid using the standard library \\, If efficiency is a significant concern, and the lists involved may be long, yes, you should. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] exceptions vs. Either
On 03-Aug-2004, Evan LaForge [EMAIL PROTECTED] wrote: In response to the mysterious head exceptions thread, isn't there a way to compile with profiling and then get the rts to give a traceback on exception? There is, but it doesn't really work properly, due to - lazy evaluation - tail call optimization - lack of line numbers in the traceback -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Ord (IORef a)?
On 22-Jun-2004, Simon Peyton-Jones [EMAIL PROTECTED] wrote: My own view is that this is fine -- IORefs shouldn't be in your inner loop, so an extra word in each is no big deal. I find that attitude rather extraordinary and I do not agree. For some applications, IORefs may well be a major contributor to memory usage, and increasing the amount of space that they take up may significantly decrease locality and hence performance. -- Fergus J. Henderson | I have always known that the pursuit Galois Connections, Inc.| of excellence is a lethal habit Phone: +1 503 626 6616 | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Preventing/handling space leaks
On 08-Dec-2003, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: G'day all. Quoting Sven Panne [EMAIL PROTECTED]: Granted, C++'s (copy) constructors, destructors and assignment operators make some things relatively easy compared to C, but the complexity of handling exceptions *correctly* makes things worse again: There is a famous article (I can't remember the title or the author) where a well-known C++ grandmaster explains a stack class, but another later article by someone else describes the numerous bugs in that class when exceptions are taken into account. Far be it from me to defend C++, but this problem is far better understood today than when that GoTW article (circa 1996, from memory) was written. The problems are certainly better understood. But they are also certainly NOT understood well enough for programmers to be able to reliably avoid them. Even the C++ standard library itself, which has been subject to review by the world's best C++ experts, suffers from exception safety problems. A new exception safety problem with std::auto_ptr was discovered just last Friday! See http://groups.google.com.au/groups?selm=uptf3hzya.fsf%40boost-consulting.com. Note that this class has already been the subject of extensive analysis of its exception safety, and indeed the only reason that auto_ptr was introduced in the first place was in an attempt to help guarantee exception safety! -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: type of (/) ?
On 09-Dec-2003, Yaroslav Korchevsky [EMAIL PROTECTED] wrote: my_avg list = (accum list) / 5 --works fine xx = 5 my_avg list = (accum list) / xx --doesn't work -- same message as above The infamous monomorphism restriction (Haskell Report section 4.5.5) strikes again. -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Preventing/handling space leaks
On 06-Dec-2003, Sven Panne [EMAIL PROTECTED] wrote: Henk-Jan.van.Tuyl wrote: [...] it looks to me, that the problem of space leaks is a very good reason to not use Haskell for commercial applications. Java, for example, does not have this problem. I just can't resist when I read PR statements like this (SUN's marketing department has *really* done a good job): Yes, it is just plain wrong to say that Java never has space leaks. Granted, Haskell has problems with space leaks from time to time, and it is especially easy for beginners to stumble over them, The problem with Haskell is not so much that beginners sometimes stuble on space leaks -- the problem is that even seasoned experts have great difficulty analyzing the space usage of very simple Haskell programs. But for large realistic programs most programming languages converge and you basically have the choice of what kind of space leak you want: If you are suggesting that space leaks are equally frequent and equally easy to diagnose and avoid in these different languages, then I would disagree. * C: Missing calls to free(), etc. For C, leaks are common because it is easy to forget to insert calls to free(), and avoiding or fixing them can be difficult because figuring out when it is safe to call free() requires a non-local analysis to figure out when data is no longer used. * C++: All of C's leaks + lots of hard to find space leaks due to incorrectly handled exceptions + ... C does suffer from many of the same problems as C. But in C++, it is much easier to automate techniques like reference counting, which can be done manually in C but are much more cumbersome and error-prone when done manually. * Haskell: Functions which are not strict enough, thunks which are never evaluated but hold large data structures, etc. Yes. The difficulty with Haskell is that everything is lazy by default. There is no explicit syntax required to define a lazy function, so if you want to figure out which functions are too lazy, you may need to examine *every* function. There is often no explicit syntax for creating a thunk, so again it is difficult to spot which parts of the program are doing this. * Java: Listeners which are not de-registered, containers which are not nulled after removal of an element, In general Java can suffer from space leaks if variables which will not be used are not nulled out. However, avoiding and/or fixing such problems is a lot easier in Java than in C, since determining whether a variable can safely be nulled out only requires analysing uses of that variable, rather than analysing uses of the object to which that variable points. This is a _much_ easier kind of analysis. IMHO it is probably also much easier than trying to analyze space usage of Haskell programs. badly written cache-like data structures, etc. Those can be a problem in any language. -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Global variables?
On 05-Feb-2003, Simon Peyton-Jones [EMAIL PROTECTED] wrote: | Haskell 98 has never supported separate compilation. That's why we | have hi-boot files (or something similar). | | So, yes, I'd like to know how the language designers intend to support | separate compilation in the next version. H98 has nothing to say about the separate compilation; it's an issue for the implementation. GHC does separate compilation for Haskell, and always has done. It requires the programmer to supply an auxiliary hi-boot file for one module in each mutually recursive group (and, of course, none if there is no recursion between modules). In other words, GHC doesn't support separate compilation of Haskell 98 -- it supports separate compilation of a closely related but distinct language which we can call Haskell 98 + GHC hi-boot files. -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Global variables?
On 02-Feb-2003, Jon Cast [EMAIL PROTECTED] wrote: Claus Reinke [EMAIL PROTECTED] wrote: It is the programmer's responsibility to verify that none of these problems matter in the particular case of usage. Since many advances in compiler technology tend to invalidate those verifications, it is almost impossible to guarantee safety in such cases Even with sufficiently liberal use of {-# NOINLINE #-}? Haskell Report, Appendix E (Compiler Pragmas): An implementation is not required to respect any pragma. There you went.. into one of the many available traps in this mine-field: You argue that unallocated IORefs don't matter as long as the IORef is allocated before it is dereferenced. But that's just part of the problem - what about inlining globalVar, creating multiple IORefs? {-# NOINLINE globalVar #-} :) What about creating two copies of globalVar, neither of them inlined? A compiler could do that to improve performance on some architectures, e.g. by allowing the function to be called via a short jump instruction rather than a long jump instruction. -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Error Handling
On 10-Dec-2002, Alastair Reid [EMAIL PROTECTED] wrote: On Sun, 8 Dec 2002, John Meacham wrote: (snip) throw (userException foo) + throw (userException bar) without defining an evaluation order you cannot know which exepction is to be thrown. catching the exception in the IO monad makes this 'okay' (snip) Mark Carroll [EMAIL PROTECTED] writes: Would it help if you defined an order over the possible exceptions, then if one is thrown you evaluate other parts of the expression to see if they also threw one, and return the first according to the ordering? I still haven't given up my hope for simple exceptions without monads. (-: To do this, we have to actually build the set of all exceptions that an expression could raise. This could take quite a while to build (lots more evaluation may need to be done) [playing devil's advocate for a moment] The set of all exceptions only needs to be built if an exception is actually raised. If no exception is raised, couldn't the code run just as fast as it currently does in Haskell? (My answer: yes, in theory it could; but only at the cost of major code bloat in the generated code and major increases in the degree of complication of the compiler. It's not worth the trade-off.) and getting any one exception probably isn't going to be any more useful than the 'random' choice you get at present. The advantage of what Mark Carroll was suggesting is not that you would get a more useful exception, just that you get a more predictable one, and that you don't need to use Monads. (My response: the potential advantages of more deterministic behaviour and [slightly] reduced need to use Monads would be outweighed by the drawbacks mentioned above, i.e. code bloat and compiler complexity.) And even this wouldn't get rid of the monads since the problem monads deal with is present even if we can't observe the exceptions. For example, a simple operation like this: choose :: a - a - a which returns its first argument if it can evaluate its argument to WHNF without raising an exception and returns its 2nd argument otherwise has severe semantic problems. That depends on what kind of exceptions you are trying to catch, doesn't it? If you need to catch out-of-memory errors (e.g. stack overflow or heap overflow), yes, that would cause semantic problems. Likewise for asynchronous exceptions/signals such as time-outs or user interrupts. But if `choose' is only catching exceptions raised by explicit calls to throw or error, then I think it would be semantically OK, wouldn't it? (Still, most of the time you probably do want to handle those kinds of errors -- at least the out-of-memory case, anyway -- so most of the time you'd still need Monads.) -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: if - is a type constructor
On 22-Feb-2002, Cagdas Ozgenc [EMAIL PROTECTED] wrote: If (-) is a type constructor, what does its definition look like, what data constructors does it have? How does it differ from other type constructors, or maybe it doesn't? It is an abstract data type. The representation is implementation-dependent. The data constructor(s) for (-) are not accessible to programs, so you can't e.g. pattern-match against them. Implementations are likely to use a specialized representation for (-). For example, they might use something similar to the following C structure. (This is from the Mercury implementation. I hope this example doesn't raise more questions than it answers ;-) /* ** A closure is a vector of words containing: ** ** one word pointing to the closure layout structure of the procedure ** one word pointing to the code of the procedure ** one word giving the number of arguments hidden in the closure (N) ** N words representing the N hidden arguments ... */ typedef struct MR_Closure_Struct { MR_Closure_Layout *MR_closure_layout; MR_Code *MR_closure_code; MR_Unsigned MR_closure_num_hidden_args; MR_Word MR_closure_hidden_args[MR_VARIABLE_SIZED]; } MR_Closure; -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: modules, classes, instances
On 14-Dec-2001, David Feuer [EMAIL PROTECTED] wrote: Well, I've been doing some more stupid thinking, and I've decided that I am not satisfied with the module system in haskell, or the way it deals with namespaces. It seems to me that there are four kinds of things that need to be dealt with: classes, instances, types, values, and possibly some kind of ML-style structures/functors. I see no good reason not to treat a class declaration similarly to the way Haskell treats modules. For example, if I have a class class A x where f1::... f2::... I would like to access the functions by writing A.f1, A.f2, etc. There should, however, be some way to unqualify the names, the way ML allows structures to be opened. A proposal very similar to this has recently been suggested on the mercury-developers mailing list [1]. This proposal, and others related to it, have then been discussed at some length. See the threads titled Module qualification of typeclass methods [1] Automatic inclusion of modules [2], and Module system discussion [3]. One drawback with this proposal was noted by Simon Taylor: | The proposal is also a step backwards for classes that are already | defined in a module of the same name, for example library/enum.m. | With the proposed change, the methods of that class would be | enum__enum__to_int and enum__enum__from_int. Finally: I want nested modules!!! They probably couldn't be compiled separately, but they'd provide some namespace control. Mercury supports separate compilation of sub-modules. Mercury has two kinds of sub-modules, nested modules, which are physically nested in the same source file, and separate sub-modules, where the parent (containing) module just contains a `:- include_module' declaration naming the child module, and the source code for the child module occurs in a separate file. You get separate compilation of separate sub-modules. [1] http://www.cs.mu.oz.au/research/mercury/mailing-lists/mercury-developers/mercury-developers.0110/0066.html [2] http://www.cs.mu.oz.au/research/mercury/mailing-lists/mercury-developers/m ercury-developers.0111/0082.html [3] http://www.cs.mu.oz.au/research/mercury/mailing-lists/mercury-developers/m ercury-developers.0111/0097.html. -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Why no exceptions in Haskell?
On 22-Nov-2001, Keith Wansbrough [EMAIL PROTECTED] wrote: I am just curious: Why does Haskell not provide exceptions a la SML? Why does only the IO monad allow for exceptions? GHC certainly implements exceptions, along the lines described in A semantics for imprecise exceptions, Simon Peyton Jones, Alastair Reid, Tony Hoare, Simon Marlow, Fergus Henderson. Proc Programming Languages Design and Implementation (PLDI'99), Atlanta. ... and the main reason why Haskell 98 didn't incorporate this is because, well, 98 was before 99 ;-). In other words, it wasn't well understood at the time the Haskell report was being written. But I think exception support along the lines suggested in that paper and implemented in GHC is very likely to be included in the next revision of Haskell. That's my opinion, anyway, though of course I am somewhat biased on this issue! ;-) -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: a newbie's question
On 12-Oct-2001, Song Li [EMAIL PROTECTED] wrote: Hi, there, Could anybody explain what does this type defination mean : data xxx a = xxx (a -b) looks xxx can use itself as constructor(like tree) but change the type.. Interpreted literally, that declaration would actually be a syntax error; but I'll assume that your are using xxx and b as meta-variables, with xxx being replaced by a name starting with a capital letter, and with b being replaced by a type. For example, let's assume that xxx is Foo and b is Integer. data Foo a = Foo (a - Integer) This defines a type constructor named Foo of kind * - *. It also defines a data constructor named Foo of type (a - Integer) - Foo a. The type constructor and the data constructor happen to share the same name, but they are separate entities. In other words, the semantics is pretty much just the same as it would be if you wrote data Foo a = MkFoo (a - Integer) except that rather than using Foo for the name of the type constructor and MkFoo for the name of the data constructor, the original declaration overloads the name Foo to mean both the type constructor and the data constructor. For uses of the overloaded name Foo, the Haskell compiler will infer from the context which is intended. -- Fergus Henderson [EMAIL PROTECTED] | ... it seems to me that 15 years of The University of Melbourne | email is plenty for one lifetime. WWW: http://www.cs.mu.oz.au/~fjh | -- Prof. Donald E. Knuth ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: = vs -
On 10-Oct-2001, D. Tweed [EMAIL PROTECTED] wrote: On Wed, 10 Oct 2001, Mark Carroll wrote: On 10 Oct 2001, Ketil Malde wrote: (snip) function definitions. Perhaps one could have had a syntax like z a = | a == 1 - 1 | a == 2 - 3 instead, as it'd make it more consisten with the case, but I suppose there's a reason for it being the way it is. The case statement is an (snip) Ah, yes - it was this 'discrepancy' that was one of the sources of my confusion, as a == 1 obviously doesn't 'equal' 1. I think this comes about from history; in the functional languages like Miranda Orwell that preceded Haskell an extended version of the function above would have been written z a = 1 if a==1 = 2 if a==2 = 3 otherwise which looks a lot like traditional mathematics and where the equals makes sense. I'm not sure why anymore but Haskell changed the `if clause after the value' to `pattern guard | before =', so I agree it now looks as if it's stating that the pattern guard is equal to the rhs. I've heard that the company which trademarked Miranda also obtained a design patent on using syntax like that in a programming language. The enforcibility of such a design patent is IMHO legally dubious, and the application of design patents to programming languages has never been tested in court as far as I am aware. But nevertheless the mere existence of such a design patent was probably a significant disincentive to using that syntax. -- Fergus Henderson [EMAIL PROTECTED] | ... it seems to me that 15 years of The University of Melbourne | email is plenty for one lifetime. WWW: http://www.cs.mu.oz.au/~fjh | -- Prof. Donald E. Knuth ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [off-topic] LaTex for [[ ... ]]
Sorry for the off-topic post, but I figured someone here would know... can anyone please tell me how to do the double-square-bracket symbols that are often used in denotational semantics in LaTex? It's like [[ but a single symbol without the space between the two brackets. (I checked the Latex companion, but it's not listed there AFAICT.) -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Macros (Was: Interesting: Lisp as a competitive advantage)
On 04-May-2001, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] wrote: Jerzy Karczmarczuk [EMAIL PROTECTED] pisze: In Clean there are macros. They are rather infrequently used... I think they roughly correspond to inline functions in Haskell. They are separate in Clean because module interfaces are written by hand, so the user can include something to be expanded inline in other modules by making it a macro. In Haskell module interfaces are generated by the compiler, so they can contain unfoldings of functions worth inlining without explicit distinguishing in the source. I don't think that Clean's module syntax is the reason. (Or if it is the reason, then it is not a _good_ reason.) After all, compilers for other languages where module interfaces are explicitly written by the programmer, e.g. Ada and Mercury, are still capable of performing intermodule inlining and other intermodule optimizations if requested. My guess is that the reason for having macros as a separate construct is that there is a difference in operational semantics, specifically with respect to lazyness, between macros and variable bindings. However, this is just a guess; I don't know Clean very well. -- Fergus Henderson [EMAIL PROTECTED] | I have always known that the pursuit | of excellence is a lethal habit WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: What do you think about Mercury?
On 08-Apr-2001, Terrence Brannon [EMAIL PROTECTED] wrote: 1- Haskell is a pure functional language, but I don't see any support for backtracking or other logic features... but my guess is you have some way of handling this? How? The usual way of handling backtracking in Haskell is using lazy lists. See Phil Wadler's 1985 paper [1]. For an example of this, I've attached a program for solving the 8-queens problem; you can compare this one with the Mercury version in tests/benchmarks/queens.m in the mercury-tests distribution. (Probably neither this one nor the Mercury one are ideal style, but I happened to have them lying around...) So backtracking is really not that hard to emulate in a lazy functional language. Supporting logic variables and constraint solving is a lot more cumbersome, however. References [1] Philip Wadler: How to Replace Failure by a List of Successes: A method for exception handling, backtracking, and pattern matching in lazy functional languages. FPCA 1985: 113-128 -- main = print_all_solns 8 main = print_soln_count 9 print_soln_count :: Int - IO () print_soln_count n = putStrLn (show (length (solutions n))) print_all_solns :: Int - IO () print_all_solns n = sequence (map show_soln (solutions n)) solutions :: Int - [[Int]] solutions n = queens (start n) show_soln :: Show a = a - IO () show_soln soln = putStrLn (show soln) start :: Int - [Int] start n = [1 .. n] queens :: [Int] - [[Int]] queens start_posn = [ posn | posn - qperm start_posn, safe posn ] qperm :: [t] - [[t]] qperm [] = [[]] qperm (x:xs) = [(y:zs) | zs - qperm ys, (y,ys) - qdelete (x:xs) ] qdelete :: [t] - [(t,[t])] qdelete [] = [] qdelete (x:xs) = ((x,xs) : [ (y,(x:ys)) | (y,ys) - qdelete xs ]) safe :: [Int] - Bool safe [] = True safe (n:l) = nodiag n 1 l safe l nodiag :: Int - Int - [Int] - Bool nodiag _ _ [] = True nodiag b d (n:l) = d /= n - b d /= b - n nodiag b (d+1) l -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Primitive types and Prelude shenanigans
On 21-Feb-2001, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] wrote: Wed, 21 Feb 2001 12:55:37 +1100, Fergus Henderson [EMAIL PROTECTED] pisze: The documentation in the Haskell report does not say what `fromInteger' should do for `Int', but the Hugs behaviour definitely seems preferable, IMHO. Sometimes yes. But for playing with Word8, Int8, CChar etc. it's sometimes needed to just cast bits without overflow checking, to convert between "signed bytes" and "unsigned bytes". Both are desirable in different situations. But if you want to ignore overflow, you should have to say so explicitly. `fromInteger' is implicitly applied to literals, and implicit truncation is dangerous, so `fromInteger' should not truncate. There should be a different function for conversions that silently truncate. You can implement such a function yourself, of course, e.g. as follows: trunc :: (Bounded a, Integral a) = Integer - a trunc x = res where min, max, size, modulus, result :: Integer min = toInteger (minBound `asTypeOf` res) max = toInteger (maxBound `asTypeOf` res) size = max - min + 1 modulus = x `mod` size result = if modulus max then modulus - size else modulus res = fromInteger result But it is probably worth including something like this in the standard library, perhaps as a type class method. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Primitive types and Prelude shenanigans
On 15-Feb-2001, William Lee Irwin III [EMAIL PROTECTED] wrote: Some reasonable assumptions: I disagree about the reasonableness of many of your assumptions ;-) (1) lists are largely untouchable I want to be able to write a Prelude that has lists as a strict data type, rather than a lazy data type. (4) I/O libs will probably not be toyed with much (monads are good!) (5) logical values will either be a monotype or a pointed set class (may be too much to support more than a monotype) I think that that replacing the I/O libs is likely to be a much more useful and realistic proposition than replacing the boolean type. (9) probably no one will try to alter application syntax to operate on things like instances of class Applicable That's a separate issue; you're talking here about a language extension, not just a new Prelude. (10) the vast majority of the prelude changes desirable to support will have to do with the numeric hierarchy s/numeric hierarchy/class hierarchy/ -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: A sample revised prelude for numeric classes
On 11-Feb-2001, Dylan Thurston [EMAIL PROTECTED] wrote: class (Num a) = Integral a where div, mod :: a - a - a divMod :: a - a - (a,a) gcd, lcm :: a - a - a extendedGCD :: a - a - (a,a,a) -- Minimal definition: divMod or (div and mod) -- and extendedGCD, if the provided definition does not work div a b | (d,_) - divMod a b = d mod a b | (_,m) - divMod a b = m divMod a b = (div a b, mod a b) gcd a b | (_,_,g) - extendedGCD a b = g extendedGCD a b = ... -- insert Euclid's algorithm here lcm a b = (a `div` gcd a b) * b Integral has the mathematical structure of a unique factorization domain, satisfying the laws a * b === b * a (div a b) * b + (mod a b) === a mod (a+k*b) b === mod a b a `div` gcd a b === zero gcd a b === gcd b a gcd (a + k*b) b === gcd a b a*c + b*d === g where (c, d, g) = extendedGCD a b TODO: quot, rem partially defined. Explain. The default definition of extendedGCD above should not be taken as canonical (unlike most default definitions); for some Integral instances, the algorithm could diverge, might not satisfy the laws above, etc. In that case, I think it might be better to not provide it as a default, and instead to provide a function called say `euclid_extendedGCD'; someone defining an instance can then extendedGCD = euclid_extendedGCD if that is appropriate. It's so much easier to find bugs in code that you did write rather than bugs which are caused by what you *didn't* write. Of course this is not so effective if we keep the awful Haskell 98 rule that instance methods always default to bottom if not defined; but even if that rule is not changed, compilers can at least warn about that case. class (Num a, Additive b) = Powerful a b where (^) :: a - b - a I don't like the name. Plain `Pow' would be better, IMHO. Apart from those two points, I quite like this proposal, at least at first glance. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Show, Eq not necessary for Num [Was: Revamping the numeric classes]
On 11-Feb-2001, Brian Boutel [EMAIL PROTECTED] wrote: Fergus Henderson wrote: On 09-Feb-2001, Brian Boutel [EMAIL PROTECTED] wrote: Patrik Jansson wrote: The fact that equality can be trivially defined as bottom does not imply that it should be a superclass of Num, it only explains that there is an ugly way of working around the problem. ... There is nothing trivial or ugly about a definition that reflects reality and bottoms only where equality is undefined. I disagree. Haskell is a statically typed language, and having errors which could easily be detected at compile instead being deferred to run time is ugly in a statically typed language. There may be some misunderstanding here. If you are talking about type for which equality is always undefined, then I agree with you, but that is not what I was talking about. I was thinking about types where equality is defined for some pairs of argument values and undefined for others - I think the original example was some kind of arbitrary precision reals. The original example was treating functions as a numeric type. In the case of functions, computing equality is almost always infeasible. But you can easily define addition etc. pointwise: f + g = (\ x - f x + g x) Returning to the basic issue, I understood the desire to remove Eq as a superclass of Num was so that people were not required to implement equality if they did not need it, not that there were significant numbers of useful numeric types for which equality was not meaningful. The argument is the latter, with functions as the canonical example. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Instances of multiple classes at once
On 08-Feb-2001, Dylan Thurston [EMAIL PROTECTED] wrote: On Thu, Feb 08, 2001 at 09:41:56PM +1100, Fergus Henderson wrote: One point that needs to be resolved is the interaction with default methods. Consider class foo a where f :: ... f = ... f2 :: ... f2 = ... class (foo a) = bar a where b :: ... instance bar T where -- no definitions for f or f2 b = 42 Should this define an instance for `foo T'? (I think not.) Whyever not? Because too much Haskell code uses classes where the methods are defined in terms of each other: class Foo a where -- you should define either f or f2 f :: ... f = ... f2 ... f2 :: ... f2 = ... f ... Because there is no textual mention of class Foo in the instance for Bar? Right, and because allowing the compiler to automatically generate instances for class Foo without the programmer having considered whether those instances are OK is too dangerous. Think about the case of a superclass with no methods; wouldn't you want to allow automatic instances in this case? Yes. I think Marcin has a better idea: | So maybe there should be a way to specify that default definitions | are cyclic and some of them must be defined? -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Revamping the numeric classes
On 08-Feb-2001, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] wrote: I don't like the idea of treating the case "no explicit definitions were given because all have default definitions which are OK" differently than "some explicit definitions were given". I don't really like it that much either, but... When there is a superclass, it must have an instance defined, so if we permit such thing at all, I would let it implicitly define all superclass instances not defined explicitly, or something like that. At least when all methods have default definitions. Yes, I know that they can be mutually recursive and thus all will be bottoms... ... that is the problem I was trying to solve. So maybe there should be a way to specify that default definitions are cyclic and some of them must be defined? I agree 100%. It is usually written in comments anyway, because it is not immediately visible in the definitions. Yes. Much better to make it part of the language, so that the compiler can check it. (now any method definition can be omitted even if it has no default!), Yeah, that one really sucks. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Show, Eq not necessary for Num [Was: Revamping the numeric classes]
On 09-Feb-2001, Brian Boutel [EMAIL PROTECTED] wrote: Patrik Jansson wrote: The fact that equality can be trivially defined as bottom does not imply that it should be a superclass of Num, it only explains that there is an ugly way of working around the problem. ... There is nothing trivial or ugly about a definition that reflects reality and bottoms only where equality is undefined. I disagree. Haskell is a statically typed language, and having errors which could easily be detected at compile instead being deferred to run time is ugly in a statically typed language. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: O'Haskell OOP Polymorphic Functions
On 30-Jan-2001, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] wrote: Tue, 30 Jan 2001 00:13:41 -0800, Ashley Yakeley [EMAIL PROTECTED] pisze: How do I define downcast? You can use a non-standard module Dynamic present in ghc, hbc and Hugs (I don't know if it's compatible with O'Haskell). That lets you downcast to specific ground types, but it doesn't let you downcast to a type class constrained type variable. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: O'Haskell OOP Polymorphic Functions
On 30-Jan-2001, Ashley Yakeley [EMAIL PROTECTED] wrote: At 2001-01-30 02:37, Fergus Henderson wrote: class BaseClass s where downcast_to_derived :: s - Maybe Derived Exactly what I was trying to avoid, since now every base class needs to know about every derived class. This isn't really a practical way to build an extensible type hierarchy. Right. I don't know of any way to do that in Hugs/ghc without the problem that you mention. Really it needs language support, I think. (I have no idea if you can do it in O'Haskell.) Note that there are some nasty semantic interactions with dynamic loading, which is another feature that it would be nice to support. I think it's possible to add dynamic loading to Haskell 98 without compromising the semantics, but if you support dynamic type class casts, or overlapping instance declarations, then dynamically loading a new module could change the semantics of existing code, rather than just adding new code. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Type Pattern-Matching for Existential Types
On 31-Jan-2001, Lennart Augustsson [EMAIL PROTECTED] wrote: Ashley Yakeley wrote: data Any = forall a. Any a get :: Any - Maybe Char get (Any (c::Char)) = Just c -- bad get _ = Nothing -- ...but as it stands, this is not legal Haskell, according to Hugs: ERROR "test.hs" (line 4): Type error in application *** Expression : Any c *** Term : c *** Type : Char *** Does not match : _0 *** Because: cannot instantiate Skolem constant This, of course, is because the '::' syntax is for static typing. It can't be used as a dynamic pattern-test. Question: how big of a change would it be to add this kind of pattern matching? Is this a small issue, or does it have large and horrible implications? It has large and horrible implications. To do dynamic type tests you need to carry around the types at runtime. This is not something that Haskell does (at least you don't have to). But you can achieve a similar effect to the example above using the Hugs/ghc `Dynamic' type. Values of type Dynamic do carry around the type of encapsulated value. data Any = forall a. typeable a = Any a get :: Any - Maybe Char get (Any x) = fromDynamic (toDyn x) This works as expected: Main get (Any 'c') Just 'c' Main get (Any "c") Nothing Main get (Any 42) ERROR: Unresolved overloading *** Type : (Typeable a, Num a) = Maybe Char *** Expression : get (Any 42) Main get (Any (42 :: Int)) Nothing -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Problems compiling HDirect 0.17
On 03-Jan-2001, Eric Allen Wohlstadter [EMAIL PROTECTED] wrote: When I try to compile hdirect on cygwin on my NT I get a lot of complaints from ghc about bad tokens. Particularly the use of "\" to continue a line. For some reason it doesn't see it as the line continuation character. You need to make sure that the files are mounted as binary rather than as text, or vice versa. Try the cygwin `mount' command. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Will Haskell be commercialized in the future?
On 27-Nov-2000, Benjamin L. Russell [EMAIL PROTECTED] wrote: Just out of curiosity: what makes you so sure about C#? C# has some potential big problems, too: in particular, the ability to declare a portion of the code "unsafe," which can encourage unsafe programming among entrenched C/C++ programmers. That is twaddle. "Entrenched" C/C++ programmers will doubtless write bad code in any other language, just like Real Programmers and Fortran. The ability to declare a portion of the code as `unsafe' is a feature. It's like `unsafePerformIO' in Haskell! And also no worse than JNI in Java. Do you think that Haskell would be better without `unsafePerformIO'? Static checking and language support for safety are very good things; I've been a supporter of those for a long long time. But to attack C# because it offers *optional* escapes from the language-enforced checking is obtuse. This is not to say that C# doesn't have any serious problems. It does. Number one is that it's a proprietry language controlled by Microsoft, with no implementations on non-Windows platforms. Also the lack of parametric polymorphism makes it much weaker than languages like Sather and Eiffel which have been around for many years, not to mention Pizza and Generic Java. This has lead C# to copy some of Java's other flaws, such as the awful array type. C# has plenty of flaws. Please criticize it for its real flaws, not the imagined ones. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit | of excellence is a lethal habit" WWW: http://www.cs.mu.oz.au/~fjh | -- the last words of T. S. Garp. ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Intel is in the .NET?
On 25-Sep-2000, Simon Peyton-Jones [EMAIL PROTECTED] wrote: I couldn't find a description of the virtual machine or its instruction set, though I downloaded the bits. Indeed, I concluded that it must, implicitly, be a JVM implementation, which is why they didn't specify it. Has anyone else found it? I had a brief look when I saw Ketil's original article and came to the same conclusion that you did. -- Fergus Henderson [EMAIL PROTECTED] | "I have always known that the pursuit WWW: http://www.cs.mu.oz.au/~fjh | of excellence is a lethal habit" PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.