ghcjs / ghcjs-base

base library for GHCJS for JavaScript interaction and marshalling, used by higher level libraries like JSC
MIT License
45 stars 67 forks source link

[Questions] #5

Closed geraldus closed 10 years ago

geraldus commented 10 years ago

@luite, I still uncertain is it good to post questions on GitHub, because it could be distracting, so please let me know if there is some better place to ask questions. I still toil with web socket connection realisation. But my first question is about types. Consider following working code:

foreign import javascript safe
    "$r = (function(){if (window.config) return window.config.gameMaker else return undefined}())"
    js_get_gmConfig :: IO (JSRef a)

-- ...
    where
        read :: IO (Maybe ModuleConfig)
        read = do
            jc <- js_get_gmConfig
            cv <- fromJSRef jc
            return $ cv >>= parseMaybe parseJSON

This works correct, here I write configuration on server side, then on client side after page loaded I try to read configuration, which may be stored in global variable config. If configuration does not exists my foreign function will return undefined value, in this case fromJSRef will return Nothing. Code above compiles and work as expected. But following code rejected by compiler:

foreign import javascript safe "$r = (function () {\
        \var conn = new WebSocket($1);\
        \conn.onmessage = $2;\
        \conn.onopen = $3;\
        \conn.onclose = $4;\
        \return conn;})()"
    js_newWebSocket :: JSString
                    -> JSFun (JSRef a -> IO ())
                    -> JSFun (IO ())
                    -> JSFun (IO ())
                    -> IO WebSocket
configuredWebSocketConnection :: String -> (MessageEvent -> IO ()) -> IO () -> IO () -> IO WebSocket
configuredWebSocketConnection url onms onop oncl = do
    onmscb <- syncCallback1 AlwaysRetain False (readMsg onms) -- :: (JSRef a -> IO b)
    onopcb <- syncCallback AlwaysRetain False onop
    onclcb <- syncCallback AlwaysRetain False oncl
    js_newWebSocket (toJSString url) onmscb onopcb onclcb
    where
        readMsg :: (MessageEvent -> IO()) -> JSRef a -> IO () -- line 56
        readMsg f jsm = do
            mv <- fromJSRef jsm
            case mv >>= parseMaybe parseJSON of  -- line 59
                Just evt -> f evt
                _        -> reportError "Unexpected message from web socket recieved."

Here is error message:

GDom/WebSockets.hs:59:36:
    Couldn't match type ‘a’ with ‘Value’
      ‘a’ is a rigid type variable bound by
          the type signature for
            readMsg :: (MessageEvent -> IO ()) -> JSRef a -> IO ()
          at GDom/WebSockets.hs:56:20
    Expected type: a
                   -> aeson-0.8.0.0:Data.Aeson.Types.Internal.Parser MessageEvent
      Actual type: Value
                   -> aeson-0.8.0.0:Data.Aeson.Types.Internal.Parser MessageEvent
    Relevant bindings include
      mv :: Maybe a (bound at GDom/WebSockets.hs:58:13)
      jsm :: JSRef a (bound at GDom/WebSockets.hs:57:19)
      readMsg :: (MessageEvent -> IO ()) -> JSRef a -> IO ()
        (bound at GDom/WebSockets.hs:57:9)
    In the first argument of ‘parseMaybe’, namely ‘parseJSON’
    In the second argument of ‘(>>=)’, namely ‘parseMaybe parseJSON’

The question is why first time I have no issue with treating JSRef a with JSRef Value, but second time compiler abuses? Sorry, this question is more about Haskell in general rather than about GHCJS. Update: I guess I've understood why its happening. Just closing this one, sorry for noise. I will ask second question in ghcjs's main repository.