forall a
types in some GHC messages or in other person's code, but I couldn't get the point of it until I needed to use it myself. I was writing a Gtk2hs application with some windows, and I noticed that for each created window, I was doing the same steps. So I created a function that does what is needed for each function:basic :: WidgetClass widget => String -> IO (Widget, (GObject -> Widget) -> String -> IO widget)
basic gladeFile =
do
(windowGlade :: GladeXML) <- getGlade gladeFile
let
windowGet :: Get
windowGet = xmlGetWidget windowGlade
(window :: Widget) <- windowGet castToWidget "window"
(close :: Button) <- windowGet castToButton "close"
onClicked close $ widgetDestroy window
modifyIORef windows (window :)
return (window, windowGet)
Notice that this code uses GHC extension PatternSignatures, which I like a lot.
The problem was that the returned function,
windowGet
was not generalized enough, so I couldn't use it with more than one type, even it being very general:windowGet :: WidgetClass widget => (GObject -> widget) -> String -> IO widget
If I used it with, say,
windowGet castToButton "ok"
and WindowGet castToSpinButton "value"
, it would give, in the seconde line, the type error: Couldn't match expected type `Button' against inferred type `SpinButton'.After asking in #haskell, and reading a little bit of the GHC User's Guide, I got the point. This was only possible with Rank 2 Types. windowGet must be:
windowGet :: forall widget. WidgetClass widget => (GObject -> widget) -> String -> IO widget
So I changed the type signature for
basic
, and added Rank2Types to the LANGUAGE pragma, and it worked fine.basic :: String -> IO (Widget, forall widget. WidgetClass widget => (GObject -> Widget) -> String -> IO widget)
Nenhum comentário:
Postar um comentário