Type tree traversals [Re: Modeling multiple inheritance]
Brandon Michael Moore
brandon at its.caltech.edu
Tue Oct 21 19:18:37 EDT 2003
This seems to work. The type checker picks one rule to use at each point
so you can't get backtracking, but you explicitly build the sequence of
base classes, and use the overloading resolution to stop if we find our
goal. This is clever.
It looks like prolog could be interesting. My first introduction to
functional programming was Unlambda (and I didn't run screaming), and it
seems the Haskell type class system is being my introduction to logic
programming. I get into paradigms the oddest ways.
Let's see if I understand the algorithm. It looks like the instances for
HasBarMethods implement a search through the ancestors of a class, with an
axiom that stops if the topmost class on the stack is the one we are
looking for, discards the top class if is Object or (), unpacks it if it
is a tuple, otherwise replaces it with the tuple of parents.
I've modified the code to express searches for multiple base classes, but
the list of classes defining a method needs to be hardcoded. I want a
solution that doesn't require any global analysis of the interface I'm
generating bindings for. I think I could do something similar with
explicitly iterating over all the methods on all the classes I hit,
with special merker types for each method name, but I haven't worked it
out yet.
P.S to implementors: backtracking search in the type class resolution
would make this sort of thing much easier to code
Brandon
---------------- Classes.hs
{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances
-fallow-overlapping-instances #-}
module Classes where
data Object = Object
data ClassA = ClassA
data ClassB = ClassB
data ClassC = ClassC
data ClassD = ClassD
class SubClass super sub | sub -> super
instance SubClass (Object,()) ClassA
instance SubClass (Object,()) ClassB
instance SubClass (ClassA,()) ClassC
instance SubClass (ClassB,()) ClassD
{- O
/ \
A B
| |
C D
-}
class HasBarMethod cls args result where
bar :: cls -> args -> result
instance HasAncestors cls (ClassA,(ClassB,())) => HasBarMethod cls args
result where
bar obj args = undefined
instance HasBarMethod ClassA args result where
bar obj args = undefined
instance HasBarMethod ClassB args result where
bar obj args = undefined
class HasFooMethod cls args result where
foo :: cls -> args -> result
instance HasAncestor cls ClassA => HasFooMethod cls args result where
foo obj args = undefined
instance HasFooMethod ClassA args result where
foo obj args = undefined
class HasBazMethod cls args result where
baz :: cls -> args -> result
instance HasAncestor cls ClassB => HasBazMethod cls args result where
baz obj args = undefined
instance HasBazMethod ClassB args result where
baz obj args = undefined
class HasAncestor cls t
--instance (SubClass supers cls,HasAncestorS supers t) =>
HasAncestor cls t
instance (SubClass supers cls, HasAncestorS cls supers (t,())) =>
HasAncestor cls t
class HasAncestors cls ts
instance (SubClass supers cls, HasAncestorS cls supers ts) =>
HasAncestors cls ts
class HasAncestorS start cls c
instance HasAncestorS start (t,x) (t,y)
instance (HasAncestorS start cls (t,ts)) =>
HasAncestorS start (Object,cls) (t,ts)
instance (HasAncestorS start cls (t,ts)) =>
HasAncestorS start ((),cls) (t,ts)
instance (SubClass supers c, HasAncestorS start (supers,cls) ts) =>
HasAncestorS start (c,cls) ts
instance (SubClass supers start, HasAncestorS start supers ts) =>
HasAncestorS start () (t,ts)
instance (HasAncestorS start (a,(b,cls)) (t,ts)) =>
HasAncestorS start ((a,b),cls) (t,ts)
------then in GHCI
--test bar
*Classes> bar ClassA 0
*** Exception: Prelude.undefined
*Classes> bar ClassA 0
*** Exception: Prelude.undefined
*Classes> bar ClassB 0
*** Exception: Prelude.undefined
*Classes> bar ClassC 0
*** Exception: Prelude.undefined
*Classes> bar ClassD 0
*** Exception: Prelude.undefined
--test foo
*Classes> foo ClassA 0
*** Exception: Prelude.undefined
*Classes> foo ClassB 0
<interactive>:1:
No instance for (HasAncestorS ClassB (Object, ()) ())
arising from use of `foo' at <interactive>:1
In the definition of `it': it = foo ClassB 0
*Classes> foo ClassC 0
*** Exception: Prelude.undefined
*Classes> foo ClassD 0
<interactive>:1:
No instance for (HasAncestorS ClassD (ClassB, ()) ())
arising from use of `foo' at <interactive>:1
In the definition of `it': it = foo ClassD 0
--test baz
*Classes> baz ClassA 0
<interactive>:1:
No instance for (HasAncestorS ClassA (Object, ()) ())
arising from use of `baz' at <interactive>:1
In the definition of `it': it = baz ClassA 0
*Classes> baz ClassB 0
*** Exception: Prelude.undefined
*Classes> baz ClassC 0
<interactive>:1:
No instance for (HasAncestorS ClassC (ClassA, ()) ())
arising from use of `baz' at <interactive>:1
In the definition of `it': it = baz ClassC 0
*Classes> baz ClassD 0
*** Exception: Prelude.undefined
More information about the Haskell-Cafe
mailing list