
{-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-overlapping-instances #-} {- Hi Mike, You might heterogeneous lists useful. http://www.cwi.nl/~ralf/HList/ See the treatment of your example below. Cheers, Ralf -} import HList import HTypeDriven -- These are your two "implementations". data MyImplementation1 = MyImplementation1 Int deriving (Show,Eq) data MyImplementation2 = MyImplementation2 Int deriving (Show,Eq) -- This is your interface class and the two instances. class MyInterface a where foo :: a -> Int instance MyInterface MyImplementation1 where foo (MyImplementation1 i) = i instance MyInterface MyImplementation2 where foo (MyImplementation2 i) = i -- Here is your list, -- without the noise you don't like. list1 = MyImplementation1 10 .*. MyImplementation2 20 .*. HNil -- If you like, this is the type, but it is not needed. -- This list is not opaque. Less trouble in our experience. -- (When compared to using existentials.) type MyList = MyImplementation1 :*: MyImplementation2 :*: HNil -- Perhaps you want to make sure that you have a list of implementations -- of MyInterface. Here is *one* way to do it. But you don't need to this -- because this will be automatically checked (statically) whenever you -- try to use the fooISH interface. class ListOfMyInterface l where listOfMyInterface :: l -> l listOfMyInterface = id instance ListOfMyInterface HNil instance ( MyInterface e , ListOfMyInterface l ) => ListOfMyInterface (HCons e l) -- So you apply the id function with the side effect of statically -- ensuring that you are given a list of implementations of MyInterface. list2 :: MyList list2 = listOfMyInterface list1 -- Here is another way to do it. -- You apply a heterogenous fold to the list. -- This second solution is just for fun. data ImplementsMyInterface = ImplementsMyInterface instance HApply ImplementsMyInterface (e,l) (HCons e l) where hApply _ (e,l) = HCons e l myKindOfList l = hFoldr ImplementsMyInterface HNil l -- Basically again you apply the identity function; a deep one this time. list3 :: MyList list3 = myKindOfList list1 -- Your quality can indeed not work because the existentially quantified -- implementations are of course opaque. You can just compare apples and -- oranges. Equality of heterogeneous lists is trivial; it is just derived. -- To make it a little bit more interesting, we can consider heterogeneous -- or stanamic equality. So you will always get a Boolean even for lists -- of different types. See below. -- Here is your bar function -- It uses one sort of maps on heterogeneous lists. bar :: MyList -> Int bar = sum . hMapOut Foo data Foo = Foo -- type driver for class-level application instance MyInterface e => HApply Foo e Int where hApply _ e = foo e {- Demo follows. *Main> :l gh-users-040607.hs Compiling FakePrelude ( ./FakePrelude.hs, interpreted ) Compiling HType ( HType.hs, interpreted ) Compiling HList ( ./HList.hs, interpreted ) Compiling HArray ( ./HArray.hs, interpreted ) Compiling HTypeDriven ( ./HTypeDriven.hs, interpreted ) Compiling Main ( gh-users-040607.hs, interpreted ) Ok, modules loaded: Main, HTypeDriven, HArray, HList, HType, FakePrelude. *Main> list1 HCons (MyImplementation1 10) (HCons (MyImplementation2 20) HNil) *Main> bar list1 30 *Main> list1 == list1 True *Main> list1 `hEqList` hReverse list1 False *Main> -} {- Mike Aizatsky wrote:
Hello,
I'm in process of rewriting the old Java application. While this is for sure lots of fun, there're some problems in modeling the java interfaces.
Here's the common Java scenario (it's actually the pattern, common for all OO-languages, so there should be no problems in understanding it):
interface MyInterface { int foo(); }
class MyImplementation1 implements MyInterface { int foo() {...} } class MyImplementation2 implements MyInterface { int foo() {...} }
And, somewhere in the code:
int bar(List<MyInterface> list) { .... sum up all foos & return .... }
I've found quite an obvious translation of it to Haskell:
module Ex where
class MyInterface a where foo :: a -> Int
data AnyMyInterface = forall a. (MyInterface a) => AnyMyInterface a
instance MyInterface AnyMyInterface where foo (AnyMyInterface a) = foo a
data MyImplementation1 = MyImplementation1 Int
instance MyInterface MyImplementation1 where foo(MyImplementation1 i) = i
data MyImplementation2 = MyImplementation2 Int
instance MyInterface MyImplementation2 where foo(MyImplementation2 i) = i
type MyList = [AnyMyInterface]
list1 :: MyList list1 = [AnyMyInterface (MyImplementation1 10), AnyMyInterface (MyImplementation2 20)]
bar :: MyList -> Int bar l = sum (map foo l)
However there're some problems with this way to go:
1. It's quite verbose. I already have a dozen of such interfaces, and I'm a bit tired of writing all this AnyInterface stuff. I'm already thinking about writing the Template Haskell code to generate it. Is anything similar available around?
2. I don't like the fact that I need to wrap all implementations inside the AnyMyInterface when returning values (see list1). Any way to get rid of it?
3. The big problem. I can't make AnyMyInterface to be an instance of Eq. I write:
data AnyMyInterface = forall a. (MyInterface a, Eq a) => AnyMyInterface a instance Eq AnyMyInterface where (==) (AnyMyInterface a1) (AnyMyInterface a2) = a1 == a2
And it gives me an error (ghc 6.2.1):
Inferred type is less polymorphic than expected Quantified type variable `a1' is unified with another quantified type variable `a' When checking an existential match that binds a1 :: a a2 :: a1 The pattern(s) have type(s): AnyMyInterface AnyMyInterface The body has type: Bool In the definition of `==': == (AnyMyInterface a1) (AnyMyInterface a2) = a1 == a2 In the definition for method `=='
Honestly, I don't understand what's going on. My guess is that the problem comes from the fact that a1 & a2 might be of different Implementations. Is it right? Any way to define the Eq instance of AnyMyInterface?
So, it looks like that existential data types do allow you to mimic the polymorphic data structures, found in OO languages. But it results in much more verbose code. Are there any other ways to do the same stuff?
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
-}