RE: Restricted Types and Infinite Loops

Simon
You've found an interesting case.
First, you are skating on thin ice here. GHC's ability to build
recursive dictionaries is quite experimental, and you are relying on it
completely.
But you're right: it "should" work. I can see why it isn't but I have
not got it clear enough in my head to know the best way to fix it.
Still less do I have a formal story about what should type-check
(without loops) and what should not.
So this is going to continue to fail in 6.4, but it's on my list to look
at.
Simon
| -----Original Message-----
| From: glasgow-haskell-users-bounces@haskell.org
[mailto:glasgow-haskell-users-
| bounces@haskell.org] On Behalf Of Simon David Foster
| Sent: 27 January 2005 14:11
| To: GHC Users
| Subject: Restricted Types and Infinite Loops
|
| Hi,
|
| (I've attached the full code for this problem)
|
| First I'll explain the problem description, I have two class ClassA
and
| ClassB, the former has two parameters and the latter has one. The
second
| parameter of ClassA is constrained by ClassB.
|
| class ClassB a where
| class ClassB b => ClassA a b where
|
| Because I wish to effectively pass the context of ClassA around, I
need
| to create a pair of dictionary types (as in Restricted Data Types in
| Haskell, Hughes 99), one to represent ClassA (DictClassA) and one to
| represent ClassB (DictClassB). DictClassA also contains a term of type
| DictClassB since ClassA is a subclass of ClassB. I should then be able
| to call all the functions of ClassB via the appropriate term of
| DictClassA, like so (assuming we want to use func2);
|
| *Test> func2D (classBD (dict::DictClassA Int String)) "hello"
| "bye"
|
| So far so good, but now suppose I want Class A to have the further
| constraint
|
| class (Data (DictClassA a) b, ClassB b) => ClassA a b where
|
| (so as to make ClassA a subclass of Data)
|
| If we now try and do
|
| *Test> func2D (classBD (dict::DictClassA Int String)) "hello"
|
| We go into an infinite loop. Why? The expression still type-checks ok
| and I can't see what it is trying to do. All the functions of ClassA
can
| be accessed ok, but not ClassB.
|
| *Test> funcD ((dict::DictClassA Int String)) "hello" 5
| "hello"
|
| Is it something to do with ClassB only having one parameter?
|
| I'm running GHC 20041231.
|
| -Si.
|
| --
| Simon David Foster

Hi Simon (PJ), cc Simon (DF), I rather reckon we are facing a bug here. The attached minimalised Foo.hs shows the offending code pattern. With GHC 6.2 we get "*** Exception: <<loop>> With GHC 6.4 we get " (still waiting for the rest of the string) The scenario is about class/instance-head-level recursion through superclassing and instance constraints. Nothing too weird. There are no _explicit_ recursive dictionaries. An observations though. The relevant class head does not just mention a recursive superclass, but also an innocent superclass ClassB. If we move this innocent superclass constraint to the instance level (see Bar.hs), then we get termination with both 6,2 and 6.4. Another issue. This feature seems to need multi-parameter classes really! Ralf Simon Peyton-Jones wrote:
Simon
You've found an interesting case.
First, you are skating on thin ice here. GHC's ability to build recursive dictionaries is quite experimental, and you are relying on it completely.
But you're right: it "should" work. I can see why it isn't but I have not got it clear enough in my head to know the best way to fix it. Still less do I have a formal story about what should type-check (without loops) and what should not.
So this is going to continue to fail in 6.4, but it's on my list to look at.
Simon
-- Ralf Lammel ralfla@microsoft.com Microsoft Corp., Redmond, Webdata/XML http://www.cs.vu.nl/~ralf/ {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-} {- Try: (sat::Int -> String -> String) undefined "hello" -} module Foo where class (Sat (a -> b -> String), ClassB b) => ClassA a b class ClassB a where fun :: a -> String class Sat x where sat :: x instance ClassA a b => Sat (a -> b -> String) where sat = const fun instance ClassA a String instance ClassB String where fun = id {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-} {- Try: (sat::Int -> String -> String) undefined "hello" -} module Foo where class Sat (a -> b -> String) => ClassA a b class ClassB a where fun :: a -> String class Sat x where sat :: x instance (ClassA a b, ClassB b) => Sat (a -> b -> String) where sat = const fun instance ClassA a String instance ClassB String where fun = id
participants (2)
-
Ralf Laemmel
-
Simon Peyton-Jones