我正在 Haskell 中使用一个名为的图形库三便士-GUI http://hackage.haskell.org/package/threepenny-gui。在这个库中,主函数返回一个UI http://hackage.haskell.org/package/threepenny-gui-0.6.0.3/docs/Graphics-UI-Threepenny-Core.html#t:UI单子对象。当我试图打开包装时,这让我非常头痛IO
值到局部变量中我收到错误,抱怨不同的 monad 类型。
这是我的问题的一个例子。这是标准 main 函数的稍微修改版本,如 Threepenny-GUI 的代码示例所示:
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = do
labelsAndValues <- shuffle [1..10]
shuffle :: [Int] -> IO [Int]
shuffle [] = return []
shuffle xs = do randomPosition <- getStdRandom (randomR (0, length xs - 1))
let (left, (a:right)) = splitAt randomPosition xs
fmap (a:) (shuffle (left ++ right))
请注意第五行:
labelsAndValues <- shuffle [1..10]
返回以下错误:
Couldn't match type ‘IO’ with ‘UI’
Expected type: UI [Int]
Actual type: IO [Int]
In a stmt of a 'do' block: labelsAndValues <- shuffle [1 .. 10]
至于我的问题,我如何解压IO
使用标准箭头符号的函数(<-
),并继续将这些变量设置为IO ()
而不是UI ()
,这样我就可以轻松地将它们传递给其他函数。
目前,我发现的唯一解决方案是使用liftIO http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html#v:liftIO,但这会导致转换为UI
monad 类型,而我实际上想继续使用IO
type.
A do
block是针对特定类型的monad,你不能只改变中间的类型。
您可以转换操作,也可以将其嵌套在do
。大多数时候,转变已经为你准备好了。例如,您可以有一个嵌套的do
与io
然后仅在交互点进行转换。
在你的情况下,liftIOLater
ThreePennyUI 包提供了函数来为您处理这个问题。
liftIOLater :: IO () -> UI ()
安排稍后运行的 IO 操作。
为了执行相反的转换,您可以使用runUI
:
runUI :: Window -> UI a -> IO a
在特定浏览器窗口中执行 UI 操作。还运行所有计划的 IO 操作。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)