Hi Fritz, | When this (incompletely-defined) function is applied to some short sample | lists expressed with the ellipsis notation, an error message is generated | (which is of course desirable), but the message generation itself seems | to loop: | ... | I hope this information is helpful. I'd be curious to hear about how the | bug (assuming it's considered to be one) comes about (clearly takeWhile | and compare are involved, but I don't see where the looping behavior | comes in). This kind of behavior has been reported previously; I'll attach copies of the earlier report, and of my reply explaining why it occurs. In summary, the Hugs printer ends up displaying part of one of the dictionaries that (a) are used in the implementation of overloading, and (b) contain cyclic structures. Some parts of the implementation have changed a little since then, but the underlying principles are still the same. Perhaps Hugs could be made to abort the display of an error message beyond a certain number of characters or depth ... folks might still be confused by the output, but at least it won't take forever to display ... All the best, Mark ---------------------------------------------------------------------------- [EMAIL PROTECTED] Pacific Software Research Center, Oregon Graduate Institute Looking for a PhD or PostDoc? Interested in joining PacSoft? Let us know!
The following program class Eq a => ShowEq a where isEq :: a -> String instance ShowEq Bool where isEq n | n == not n = "Strange" gives: Main> isEq True " Program error: {instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 (instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 ..... Obviously a cyclic term gives an infinite error message. But why is there anything cyclic in this situation? Cheers, Olaf -- OLAF CHITIL, Lehrstuhl fuer Informatik II, RWTH Aachen, 52056 Aachen, Germany Tel: (+49/0)241/80-21212; Fax: (+49/0)241/8888-217 URL: http://www-i2.informatik.rwth-aachen.de/~chitil/
| The following program | | class Eq a => ShowEq a where | isEq :: a -> String | | instance ShowEq Bool where | isEq n | n == not n = "Strange" | | gives: | Main> isEq True | " | Program error: {instShowEq_v1885_v1898 (Make.ShowEq instEq_v97 | ... | Obviously a cyclic term gives an infinite error message. | But why is there anything cyclic in this situation? I think we're in agreement than an error message of some form is what you would expect ... the question is "why this particular error message?" To understand that, I'm afraid you need to look under the hood at the dictionary translation used in Hugs. First, the class definition is translated into the following dictionary datatype: data ShowEq a = Make.ShowEq {sc1 :: Eq a, isEq :: a -> String) (I'm showing (mostly) the actual names that Hugs uses. Don't think of the "." here as composition, or qualified names. There's just one name here, "Make.ShowEq", and the presence of the "." means that it won't clash with any names that programmers can write.) We also get a default constructor for ShowEq dictionaries: defaultShowEq :: Eq a -> ShowEq a -> ShowEq a defaultShowEq eqd d = Make.ShowEq eqd (error "undefined isEq member") The d parameter here is used to support default definitions in classes that have them. Sometimes, this in itself can lead to cyclic terms. In this case, it's not actually used because the class doesn't have any defaults. Nevertheless, it's part of the protocol, so it has to be there. The Eq type here is the corresponding dictionary type for the Eq class. Assuming that we've defined an instance for Eq Bool, there is a constant floating around that holds this dictionary. In this case, the name that Hugs has assigned to that dictionary is displayed as: instEq_v97 :: Eq Bool Now let's look at your instance declaration, which is translated to the following code: instShowEq_v1885 :: ShowEq Bool instShowEq_v1885 = d where d = (defaultShowEq instEq_v97 d){isEq = thisIsEq} thisIsEq n | (==) (sc1 d) n (not n) = "Strange" ^^(1)^^ Here, marked by (1) is the source of the behaviour that you're going to see. Instead of taking the equality on Bool from the global instance, it looks at the instance stored within the dictionary. In general, this is the only option, because the dictionary that you're looking for won't be a global constant. But let's finish off this example ... After lambda-lifting, thisIsEq gets moved to the top-level where it gets a new name, instShowEq_v1885_v1898, and an extra parameter: instShowEq_v1885 :: ShowEqDict Bool instShowEq_v1885 = d where d = (defaultShowEq instEq_v97 d){isEq = instShowEq_v1885_v1898 d} (2)^ (3)^ instShowEq_v1885_v1898 d n | (==) (sc1 d) n (not n) = "Strange" Note the two apparently cyclic references to d here. (2) is the innocuous one that we've already mentioned above. It doesn't actually lead to a cyclic structure here because the class doesn't have any default definitions. (3) is the carry over from (1), and will result in a cyclic structure. We're nearly there. Now you type in isEq True, which gets translated to: isEq instShowEq_v1885 True Alas, because your definition doesn't have any cases that match this call, Hugs cannot do anything with it, so it tries to display an error message. Unfortunately, that involves printing an infinite, cyclic data structure, which means that the error message takes a long time to display... In summary: In special cases, like yours, there is no need for a cyclic structure. But in general, it is unavoidable. Hope that helps ... and now that we've finished looking at the greasy machinery under the hood, we can all go wash our hands, relieved that we don't usually have to write this kind of code ourselves! All the best, Mark
