具有多种 monad 类型的 Haskell do 子句

标签 haskell monads threepenny-gui

我正在 Haskell 中使用一个名为 Threepenny-GUI 的图形库。在这个库中,主函数返回 UI 单子(monad)对象。当我尝试打开包装时,这让我非常头痛 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 ,但这会导致转换为 UI monad 类型,而我实际上想继续使用 IO类型。

最佳答案

do block 适用于特定类型的 monad,您不能只更改中间的类型。

您可以转换操作,也可以将其嵌套在 do 中。大多数时候,转变已经为你准备好了。例如,您可以拥有一个与 io 配合使用的嵌套 do,然后仅在交互时对其进行转换。

就您而言,ThreePennyUI 包提供了一个 liftIOLater 函数来为您处理此问题。

liftIOLater :: IO () -> UI ()

Schedule an IO action to be run later.

为了执行相反的转换,您可以使用runUI:

runUI :: Window -> UI a -> IO a

Execute an UI action in a particular browser window. Also runs all scheduled IO action.

关于具有多种 monad 类型的 Haskell do 子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30981044/

相关文章:

haskell - 为什么是单子(monad)?它如何解决副作用?

haskell - 为Canvas设计一个绘图API

haskell - "reader"单子(monad)

haskell - 表示红黑树的最有效方法是什么?

multithreading - `par` 是否创建另一个线程?

haskell - 将 failWith 与 Servant 和自定义 monad 堆栈一起使用

haskell - 如何在 ADT 或记录语法上使用 Monadic 绑定(bind)运算符

haskell - 如何在 Windows 上运行 Threepenny-gui 示例

haskell - 是否可以手动更新行为的值? (功能响应式(Reactive)编程,三便士)

haskell - B计划,或者与Maybe的>>=相反的是什么?