alexanderforemny: > My general idea is to have the main application listening to the network > socket and then calling all the plugins on each incoming message. > Therefore I maintain a list of plugin states in the main application's > state and on each incoming message I call a function which modifies the > plugin's state.
Like lambdabot! > There's a PluginClass class which contains definitions of functions for > each plugin which they all share. Simplyfied it's like this: > > type PL = StateT PluginConfig > > class PluginClass a where > identifier :: a -> String > rawMessage :: (MonadIO m) => a -> Message -> PL m () Like lambdabot, kind of. > So plugins can be identified uniquely using the identifier function and > they can respond to messages using the rawMessage function. This function > is executed in the PL monad, which is essentially a StateT monad for > updating the plugin's state trough put and maybe accessing a few data > fields from the underlying Bot monad in which the main application is > operating. > > Then again I want to be able to query a plugin's state from a different > plugin. For instance I'll have a plugin which keeps track of the channels > the bot has joined collecting user information, the topic, etc. Another > plugin could then query the "chan info" plugin and get all the users in a > certain channel through a queryPlugin function which takes a plugin and > looks that plugin up in the main application's plugin state list for the > right state and then calls a function on it. The plugin and the > corresponding functions would be exported by the plugin's module. > > queryPlugin :: (PluginClass a) => a -> (a -> b) -> PL m b > queryPlugin pl f = do > plugins <- getGlobalPlugins -- ideally (PluginClass a) => [a] > let pluginNames = map identifier plugins > targetName = identifier pl > [(_, target)] = filter ((==) targetName . fst) (zip pluginNames > plugin) > return (f target) > > But here I am facing either one or the other problem, depending on the > "solution." > > 1) I somehow have to store all the plugin states in the main application. > Since plugins are essentially their states, they are quite arbitrary. I > either cannot use a list for that or I have to use existential types which > would make that possible. Existential types are used in lambdabot for this. I'd probably use an associated type to connect the plugin to its state type now, too. > 2) Using an existential plugin type would restrict the functions I am able > to call on the plugin to those which are supported by the PluginClass. > This would render queryPlugin unusable since the functions a plugin > exports for query the state are arbitrary. You might be able to design around this. Lambdabot manages ok with existentially typed interfaces. -- Don _______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
