Created
June 4, 2014 19:34
-
-
Save ruthenium/dd718c545c97df56b79d to your computer and use it in GitHub Desktop.
Inheritance and overloading with 'super' action
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# 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