How can I Handle user plugins in my types?

孤街醉人 提交于 2019-12-01 00:50:34

Of course each Plugin is going to have a different Type for the Plugin state, so I'm getting stuck on how I can integrate this into my system in a general way.

Perhaps you could use an existential type to hide the plugin state, 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 is of the same type, and yet different plugin values 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 existentials in a similar way.)

You can now have a list of plugins:

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

A possible evolution of the design would be to constrain the internal states to be instances of some typeclass:

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

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

Also, we could think of explicitly parameterizing Plugin on the type of events it accepts, like

data Plugin e = ...

In that case Plugin could be made an instance of Contravariant and perhaps Divisible as well.

And if we go wild and parameterize on the editor state

data Plugin es e = ...

then perhaps we could find a way to "zoom" a given plugin to work in a more general state than the one for which it was defined.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!