I'm stuck trying to select one instance from many at runtime. Really is a kind of Backend
.
I'm able to do it if I select one instance or other at compile time.
UPDATED probably I want some similar to Database.Persist (it define a fully behavior but many instances: mongodb, sqlite, postgresql, ...). But is too complex to me.
UPDATED using GADTs
works but I think exist a better way (full code at the bottom).
In some OOP language my problem is more or less
interface IBehavior { void foo(); }
class AppObject { IBehavior bee; void run(); }
...
var app = new AppObject { bee = makeOneOrOtherBehavior(); }
....
I've tried many ways (and lots of extensions :D) but none works.
Informally I want to define one class
with certain behavior and use this generic definition into some application, after it, select at runtime one instance
from some.
The generic behavior (not real code)
class Behavior k a where
behavior :: k -> IO ()
foo :: k -> a -> Bool
...
(I think k
is needed since each instance
could need their own context/data; other restrictions like key
/value
may be exist)
Two instances
data BehaviorA
instance Behavior BehaviorA where
behavior _ = print "Behavior A!"
data BehaviorB
instance Behavior BehaviorB where
behavior _ = print "Behavior B!"
my application use that behavior (here begin the chaos)
data WithBehavior =
WithBehavior { foo :: String
, bee :: forall b . Behavior b => b
}
run :: WithBehavior -> IO ()
run (WithBehavior {..}) = print foo >> behavior bee
I wish select at runtime
selectedBee x = case x of
"A" -> makeBehaviorA
"B" -> makeBehaviorB
...
withBehavior x = makeWithBehavior (selectedBee x)
but I'm lost into a maze of extensions, type dependencies and others :(
I cannot set the proper type for selectedBee
function.
Any help will be appreciated! :)
(Using GADTs
, but without additional a
type parameters!)
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE GADTs #-}
import System.Environment
import Control.Applicative
class Behavior k where
behavior' :: k -> IO ()
data BehaviorInstance where
BehaviorInstance :: Behavior b => b -> BehaviorInstance
behavior :: BehaviorInstance -> IO ()
behavior (BehaviorInstance b) = behavior' b
data BehaviorA = BehaviorA
instance Behavior BehaviorA where
behavior' _ = print "Behavior A!"
makeBehaviorA :: BehaviorInstance
makeBehaviorA = BehaviorInstance BehaviorA
data BehaviorB = BehaviorB
instance Behavior BehaviorB where
behavior' _ = print "Behavior B!"
makeBehaviorB :: BehaviorInstance
makeBehaviorB = BehaviorInstance BehaviorB
data WithBehavior =
WithBehavior { foo :: String
, bee :: BehaviorInstance
}
run :: WithBehavior -> IO ()
run (WithBehavior {..}) = print foo >> behavior bee
main = do
n <- head <$> getArgs
let be = case n of
"A" -> makeBehaviorA
_ -> makeBehaviorB
run $ WithBehavior "Foo Message!" be