首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有多种类型的Haskell do子句

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

Stack Overflow用户
提问于 2015-06-22 13:20:18
回答 3查看 929关注 0票数 8

我在Haskell使用一个名为三倍图形用户界面的图形库。在这个库中,main函数返回一个UI monad对象。这让我非常头疼,因为当我试图将IO值解压缩到局部变量时,我会收到错误,抱怨不同的monad类型。

这是我的问题的一个例子。这是标准main函数的稍微修改的版本,如Threepenny-GUI的代码示例所提供的:

代码语言:javascript
复制
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))

请注意第五行:

代码语言:javascript
复制
labelsAndValues <- shuffle [1..10]

返回以下错误:

代码语言:javascript
复制
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类型。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-22 13:29:38

do块是针对特定类型的monad,您不能只在中间更改类型。

您可以转换操作,也可以将其嵌套在do中。大多数情况下,转换将为您做好准备。例如,您可以拥有一个嵌套的do,它可以与io一起工作,然后只在交互点转换它。

在您的示例中,提供了一个liftIOLater函数来通过ThreePennyUI包为您处理这个问题。

liftIOLater :: IO () -> UI () 安排一个IO操作,以便稍后运行。

为了执行逆转换,可以使用runUI

runUI :: Window -> UI a -> IO a 在特定浏览器窗口中执行UI操作。还运行所有计划的IO操作。

票数 8
EN

Stack Overflow用户

发布于 2015-06-22 18:15:42

这是一个扩展的评论-它没有解决主要的问题,但您的shufffle的实现。它有两个问题:

  1. 您的实现效率很低- O(n^2)。
  2. IO不是适合它的类型--洗牌没有一般的副作用,它只是需要一个随机性的来源。

对于(1)有几种解决方案:一是使用Seq及其index,即O(log ),这将使shuffle O( n )。或者您可以使用ST 列阵和其中一个标准算法来获得O(n)。

对于(2),您所需要的只是线程化一个随机生成器,而不是IO的全部功率。已经有了一个很好的库MonadRandom,它为随机计算定义了一个单类(和一个类型类)。另外一个包已经提供了函数。因为IOMonadRandom的一个实例,所以您可以直接使用shuffle代替您的函数。

票数 5
EN

Stack Overflow用户

发布于 2015-06-22 17:15:13

在封面下,do只是用于>>= (bind)的语法糖,并让:

代码语言:javascript
复制
do { x<-e; es } =   e >>= \x -> do { es }
do { e; es }    =   e >> do { es }
do { e }        =   e
do {let ds; es} =   let ds in do {es} 

以及约束的类型:

代码语言:javascript
复制
(>>=) :: Monad m => a -> (a -> m b) -> m b

所以是的,它只“支持”一个Monad

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30981044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档