Skip to content

Instantly share code, notes, and snippets.

@ruthenium
Created June 4, 2014 19:34
Show Gist options
  • Save ruthenium/dd718c545c97df56b79d to your computer and use it in GitHub Desktop.
Save ruthenium/dd718c545c97df56b79d to your computer and use it in GitHub Desktop.
Inheritance and overloading with 'super' action
{-# LANGUAGE TypeFamilies, StandaloneDeriving #-}
{- anti-pattern warning -}
{-
Say, we need to "inherit" some behavior from another object.
Say, we also need to be able to customize overloaded actions,
preserving the ability of using the original action.
This is the one of the approaches.
-}
--------------------------------------------------------------------------------
{-
To implement this we need a basic datatype (like in those imperative
languages every class is an ancestor of `Object` )
and a special typeclass
-}
data BaseObject = BaseObject -- here can go common (inheritable) data fields
class WithInheritedActions a where
{- that's the point: -}
type BaseType a
super :: a -> BaseType a
{- inheritable actions go further: -}
action1 :: a -> IO ()
--action2 :: a -> Foo
--action3 :: a -> Bar
--------------------------------------------------------------------------------
{- first of all, a simple usage example: -}
data Object1 = Object1 { object1Base :: BaseObject }
instance WithInheritedActions Object1 where
type BaseType Object1 = BaseObject
super = object1Base
action1 a = print "object1"
{- now it's time to show inheritance and overloading: -}
data Object2 = Object2 { object2Base :: BaseObject } -- just like example above
instance WithInheritedActions Object2 where
type BaseType Object2 = BaseObject
super = object2Base
action1 a = print "object2"
data Object3 = Object3 { object3Base :: Object2 } -- note the base
instance WithInheritedActions Object3 where
type BaseType Object3 = Object2 -- note the base
super = object3Base
action1 a = do
print "object3, and..."
action1 $ super a
-- now we can do:
--main = do
-- let o = Object1 BaseObject
-- o1 = Object2 BaseObject
-- o2 = Object3 $ Object2 BaseObject
-- action1 o
-- action1 o1
-- action1 o2
{-
If one wants to use an existentially quantified typeclass,
for example, for a heterogenous list,
it also can be used to translate inherited actions
from the container to conents.
NOTE: Existentially quantified typeclass is an anti-pattern.
So kids, don`t ever think to try using it at home.
-}
--data Container = forall a. (WithInheritedActions a, Show a) => Container a
-- deriving instance Show (Container)
--instance WithInheritedActions Container where
-- type BaseType Container = ()
-- super = const ()
--
-- action1 (Container a) = action1 a
{- ofc usage example now: -}
--main = do
-- let objs = [
-- Container $ Object1 BaseObject,
-- Container $ Object3 $ Object2 BaseObject
-- ]
-- action1 $ head objs
-- action1 $ last objs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment