Qt:按钮点击=>消息应出现在haskell程序中

时间:2016-03-07 15:28:28

标签: qt ubuntu haskell sublimetext3

我尝试创建一个程序,当点击按钮时显示文本,使用haskell& Qt,在ubuntu上使用sublime text 3。 但显然在定义信号键时会出现问题(该键将识别单击按钮时调用的信号)。 此外,很难找到关于HsQML的文档,绑定加入haskell& Qt的。

代码:

module Main where

import Graphics.QML
import Control.Concurrent
import Control.Exception
import Data.IORef
import Data.Text (Text)
import qualified Data.Text as T

    main :: IO ()
    main = do
        state <- newIORef $ T.pack ""
        skey <- newSignalKey
        clazz <- newClass [
            defPropertySigRO' "my_label" skey (\_ -> readIORef state),
            defMethod' "sayHello" (\obj txt -> do
                writeIORef state txt
                fireSignal skey obj
                return ())]
        ctx <- newObject clazz ()
        runEngineLoop defaultEngineConfig {
            initialDocument = fileDocument "exemple2.qml",
            contextObject = Just $ anyObjRef ctx}

错误消息:

Build FAILED

/home/lowley/Documents/haskell/Qt/exemple-2.hs: line 13, column 10:
  No instance for (SignalSuffix (IO a0))
    arising from a use of `newSignalKey'
  The type variable `a0' is ambiguous
  Possible fix: add a type signature that fixes these type variable(s)
  Note: there is a potential instance available:
    instance SignalSuffix (IO ()) -- Defined in `Graphics.QML.Objects'
  Possible fix:
    add an instance declaration for (SignalSuffix (IO a0))
  In a stmt of a 'do' block: skey <- newSignalKey
  In the expression:
    do { state <- newIORef $ T.pack "";
         skey <- newSignalKey;
         clazz <- newClass
                    [defPropertySigRO' "my_label" skey (\ _ -> readIORef state),
                     defMethod' "sayHello" (\ obj txt -> ...)];
         ctx <- newObject clazz ();
         .... }
  In an equation for `main':
      main
        = do { state <- newIORef $ T.pack "";
               skey <- newSignalKey;
               clazz <- newClass
                          [defPropertySigRO' "my_label" skey (\ _ -> ...), ....];
               .... }

解决了! 但我想知道为什么这个程序可以在没有上述错误的情况下编译:

module Main where

import Graphics.QML
import Control.Concurrent
import Control.Exception
import Data.IORef
import qualified Data.Text as T

main :: IO ()
main = do
    state <- newIORef $ T.pack ""
    skey <- newSignalKey
    clazz <- newClass [
        defPropertySigRO' "result" skey (\_ ->
            readIORef state),
        defMethod' "factorial" (\obj txt -> do
            let n = read $ T.unpack txt :: Integer
            writeIORef state $ T.pack "Working..."
            fireSignal skey obj
            forkIO $ do
                let out = T.take 1000 . T.pack . show $ product [1..n]
                evaluate out
                writeIORef state out
                fireSignal skey obj
            return ())]
    ctx <- newObject clazz ()
    runEngineLoop defaultEngineConfig {
        initialDocument = fileDocument "factorial2.qml",
        contextObject = Just $ anyObjRef ctx}

1 个答案:

答案 0 :(得分:2)

有错误告诉您GHC不知道newSignalKey创建的信号应该具有什么类型(newSignalKey :: SignalSuffix p => IO (SignalKey p)。GHC不知道p应该是什么类型,因为你不知道t指定它)。添加如下显式类型签名:

skey <- newSignalKey :: IO (SignalKey (IO ()))

应该修复你看到的错误。

好的,那么为什么它在第二个例子中起作用呢?要理解这一点,我们必须看看GHC知道什么以及它可以确定skey的类型。

在第一个示例和第二个示例中,skey的用法如下:

do
  ...
  fireSignal skey obj
  ...

由于fireSignal :: SignalKey p -> ObjRef () -> p(简化类型,fireSignal的完整类型更为通用),GHC知道p必须是IO something,因为它在上下文中使用预期IO something操作的位置(作为IO中的do块的一部分)。它不知道something是什么,因为永远不会使用IO动作的返回值。因此保留skey :: SignalKey (IO something),并正确报告something不明确的错误(它不知道something应该是什么类型。)

在第二个例子中,skey也用于以下模式:

forkIO $ do
  ...
  fireSignal skey obj

由于forkIO期望IO操作返回类型为()的值,因此GHC现在知道fireSignal skey obj :: IO ()(所以在这种情况下,它知道{{1}必须是something)。这意味着()不再含糊不清,必须为p