This message gives an example of a dynamic type *class* cast in Haskell. We want to dispatch on a class of a type rather on a type itself. In other words, we would like to simulate IsInstanceOf. The problem was originally posed by Hal Daume III in a message "simulating dynamic dispatch" posted on Mar 20, 2003 on the Haskell mailing list: http://www.haskell.org/pipermail/haskell/2003-March/011518.html Hal Daume wrote: ] i'm hoping to be able to simulate a sort of dynamic dispatch based on ] class instances. basically a function which takes a value and depending ] on what classes it is an instance of, does something. a simple example ] might be a 'maybeShow' function which semantically looks like: ] ]> maybeShow x ]> | typeOf x `instanceOf` Show = show x ]> | otherwise = "?" ] ] I've been trying for a while to simulate something along the lines of: ] ]> class Foo a where { foo :: a -> Bool } ]> class Bar a where { bar :: a -> Bool } ]> foo x ]> | typeOf x `instanceOf` Foo = Just (foo x) ]> | typeOf x `instanceOf` Bar = Just (bar x) ]> | otherwise = Nothing ] ] The following code shows how to implement a dynamic dispatch on a type class context. No unsafe operations are used. The test at the end demonstrates that we can indeed simulate Hal's desired example. The code was originally posted on Sun, 23 Mar 2003 13:41:48 on the Haskell mailing list. http://www.haskell.org/pipermail/haskell/2003-March/011532.html The code relies on existential datatypes and runs on "hugs -98" and "ghci -fglasgow-exts" Dynamic dispatch on a constraint: Foo, Bar, or Quux First we define the classes to dispatch on: > class Foo a where { foo :: a -> String } > class Bar a where { bar :: a -> String } > class Quu a where { quu :: a -> String } and populate them: > instance Foo Int where > foo x = "this is foo calling: " ++ (show x) > > instance Bar Char where > bar x = "this is bar calling: " ++ (show x) > instance Bar Int where > bar x = "this is bar calling: " ++ (show x) > > instance Quu [Bool] where > quu x = "this is quu calling: " ++ (show x) Next we introduce the Universe (with hidden constraints) > data PACK = forall a . Foo a => MkFoo a | forall a . Bar a => MkBar a > | forall a . Quu a => MkQuu a and the packer, i.e., the injection function: > class Packable a where > pack:: a -> PACK The following three instances are the "inverse" of the instances of Foo, Bar, and Quu introduced above. A type can be a member of several type classes. The following instances resolve the ambiguity. For example, a type Int is a member of a class Foo and of a class Bar. The first instance declaration below matches Int to the class Foo. And so we would dispatch on Foo when we see an Int. > instance Packable Int where > pack = MkFoo > > instance Packable Char where > pack = MkBar > > instance Packable [Bool] where > pack = MkQuu Finally, here's the dispatcher > instance Foo PACK where > foo (MkFoo x) = foo x > > instance Bar PACK where > bar (MkBar x) = bar x > > instance Quu PACK where > quu (MkQuu x) = quu x and the test of the dynamic class dispatch: > test:: (Packable a) => a -> String > test = dispatch . pack > where > dispatch x = case x of > (MkFoo a) -> foo a > (MkBar a) -> bar a > (MkQuu a) -> quu a -- *Main> test (1::Int) -- "this is foo calling: 1" -- *Main> test 'a' -- "this is bar calling: 'a'" -- *Main> test [True,False] -- "this is quu calling: [True,False]"