我尝试创建一个程序,当使用高级文本3在ubuntu上使用Haskell&Qt在单击按钮时显示文本。但是,显然在定义信号键时会出现问题(该键将识别信号,按钮)。此外,很难找到有关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}
错误提示您GHC不知道所创建的信号newSignalKey
应具有的类型(newSignalKey :: SignalSuffix p => IO (SignalKey p)
。GHC不知道p
应为什么类型,因为您未指定它)。添加像这样的显式类型签名:
skey <- newSignalKey :: IO (SignalKey (IO ()))
应该解决您所看到的错误。
好的,那么现在为什么在第二个示例中可以工作?要了解这一点,我们必须查看GHC知道什么以及它可以确定有关的类型skey
。
在第一个示例和第二个示例中,skey
用法如下:
do
...
fireSignal skey obj
...
因为fireSignal :: SignalKey p -> ObjRef () -> p
(简化的类型,的完整类型fireSignal
更为通用),所以GHC知道p
必须为IO something
,因为它是在需要执行IO something
操作的上下文中使用的(作为的do块的一部分IO
)。它不知道是什么something
,因为IO
从不使用该操作的返回值。因此,它留有skey :: SignalKey (IO something)
,并正确地报告一个something
模棱两可的错误(它不知道something
应该是哪种类型)。
但是,在第二个示例中,也将skey用于以下模式:
forkIO $ do
...
fireSignal skey obj
由于forkIO
期望IO
返回一个type值的操作,因此()
GHC现在知道这一点fireSignal skey obj :: IO ()
(因此,在这种情况下,它知道something
必须是()
)。这意味着它p
不再是模棱两可的了IO ()
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句