How can I handle custom plugins in my types?

I am writing a modular and extensible text editor in Haskell, and I would like to implement plugins this way: the plugin writer provides one function that looks something like this:

handleEvent :: (PluginState, EditorState) -> Event -> (PluginState, EditorState) 

As soon as each event occurs, the plugin can use the current state of the editor and a custom piece of its own state to calculate the new state of the editor and the new state of the plugin. Of course, each plug-in will have a different type for the status of the plug-in, so I focus on how I can integrate it into my system in a general way.

How can I write something vaguely:

 type Plugin = (PluginState, EditorState) -> Event -> (PluginState, EditorState) data MyEditor = MyEditor EditorState [Plugin] [PluginState] 

When is a PluginState not a specific type?

TL; DR; How can I store a map of values ​​with sky types in an accessible way without baking in each state of the plugin state in my global state? I am fine with recompiling the editor when adding a new plugin.

Thanks! I am really stuck with this: /

If you need any clarification, please just ask!

+2
source share
1 answer

Of course, each plug-in will have a different type for the status of the plug-in, so I focus on how I can integrate it into my system in a general way.

Perhaps you can use the existential type to hide the state of the plugin, something like

 {-# LANGUAGE ExistentialQuantification #-} data Plugin = forall ps. Plugin { currentState :: ps , transition :: ps -> EditorState -> Event -> (ps, EditorState) } handleEvent :: Plugin -> EditorState -> Event -> (Plugin,EditorState) handleEvent (Plugin ps t) es e = let (ps',es') = t ps es e in (Plugin ps' t,es') 

Now each plugin has the same type, and yet different values ​​of the plugin can have internal states of different types:

 charPlugin :: Plugin charPlugin = Plugin 'a' (\ps es e -> (succ ps,es)) intPlugin :: Plugin intPlugin = Plugin (1::Int) (\ps es e -> (succ ps,es)) 

(I took inspiration from the Fold type from the foldl package, which uses existences in a similar way.)

Now you can have a list of plugins:

 plugins :: [Plugin] plugins = [charPlugin,intPlugin] 

A possible evolution of the project would be to limit the internal states to instances of some type:

 data Plugin = forall ps. Show ps => Plugin { currentState :: ps , transition :: ps -> EditorState -> Event -> (ps, EditorState) } 

I suspect that a Monoid instance might be defined for the Plugin type.

In addition, we could explicitly specify Plugin parameterization on the type of events that it receives, for example

 data Plugin e = ... 

In this case, the plugin could be made an instance of Contravariant and possibly Divisible .

And if we break up and parameterize the state of the editor

 data Plugin es e = ... 

then perhaps we could find a way to “enlarge” this plugin to work in a more general state than the one for which it was defined.

+1
source

Source: https://habr.com/ru/post/1015369/


All Articles