Re: Modelling Java Interfaces with Existential data types

2004-06-07 Thread Ralf Laemmel

{-# 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 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 interfac

Modelling Java Interfaces with Existential data types

2004-06-07 Thread Mike Aizatsky
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 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
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users