Let's say I have the following function:
loadDialog :: String -> IO MyDialog
loadDialog file = do
Just ui <- xmlNew file
MyDialog
<$> xmlGetWidget ui castToWindow "w"
<*> xmlGetWidget ui castToButton "b"
where
xmlGetWidget :: WidgetClass widget => GladeXML -> (GObject -> widget) -> String -> IO widget
Now I want to capture the following xmlNew/xmlGetWidget usage pattern:
widgetBinder :: WidgetClass widget => FilePath -> IO ((GObject -> widget) -> String -> IO widget)
widgetBinder file = do
Just ui <- xmlNew file
return $ xmlGetWidget ui
Which should allow me to write:
loadDialog file = do
bind <- widgetBinder file
MyDialog
<$> bind castToWindow "w"
<*> bind castToButton "b"
The problem is, it doesn't typecheck (exact error here). I've thought it's possible to provide generic signatures to bindings explicitly, but it seems this is not the case for monadic bindings since the following doesn't typecheck as well (even with RankNTypes, error here):
loadDialog file = do
bind :: WidgetClass w => (GObject -> w) -> String -> IO w
<- widgetBinder file
MyDialog
<$> bind castToWindow "w"
<*> bind castToButton "b"
Is there anything I can do?
A clunky-but-workable solution is to throw your function into a newtype
:
newtype Binder = Binder (forall w. WidgetClass w => (GObject -> w) -> String -> IO w)
widgetBinder :: FilePath -> IO Binder
widgetBinder file = do
Just ui <- xmlNew file
return $ Binder (xmlGetWidget ui)
loadDialog file = do
Binder bind <- widgetBinder file
MyDialog
<$> bind castToWindow "w"
<*> bind castToButton "b"
Or something like that...