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


Reply via email to