我在Haskell使用一个名为三倍图形用户界面的图形库。在这个库中,main函数返回一个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类型。
发布于 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操作。
发布于 2015-06-22 18:15:42
这是一个扩展的评论-它没有解决主要的问题,但您的shufffle的实现。它有两个问题:
IO不是适合它的类型--洗牌没有一般的副作用,它只是需要一个随机性的来源。对于(1)有几种解决方案:一是使用Seq及其index,即O(log ),这将使shuffle O( n )。或者您可以使用ST 列阵和其中一个标准算法来获得O(n)。
对于(2),您所需要的只是线程化一个随机生成器,而不是IO的全部功率。已经有了一个很好的库MonadRandom,它为随机计算定义了一个单类(和一个类型类)。另外一个包已经提供了函数。因为IO是MonadRandom的一个实例,所以您可以直接使用shuffle代替您的函数。
发布于 2015-06-22 17:15:13
在封面下,do只是用于>>= (bind)的语法糖,并让:
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} 以及约束的类型:
(>>=) :: Monad m => a -> (a -> m b) -> m b所以是的,它只“支持”一个Monad
https://stackoverflow.com/questions/30981044
复制相似问题