haskell - 返回类型丢失 IO

标签 haskell

我在处理这段代码中的函数共识时遇到了问题。共识的递归定义是返回 [Action] 而不是 IO [Action]

我是 Haskell 的新手,不明白为什么会这样。我的印象是不可能从返回值中删除 IO。

import System.Random (randomRIO)
import Data.Ord (comparing)
import Data.List (group, sort, maximumBy)

data Action = A | B deriving (Show, Eq, Ord)

-- Sometimes returns a random action
semiRandomAction :: Bool -> Action -> IO (Action)
semiRandomAction True a = return a
semiRandomAction False _ = do
  x <- randomRIO (0, 1) :: IO Int
  return $ if x == 0 then A else B

-- Creates a sublist for each a_i in ls where sublist i does not contain a_i
oneOutSublists :: [a] -> [[a]]
oneOutSublists [] = []
oneOutSublists (x:xs) = xs : map (x : ) (oneOutSublists xs)

-- Returns the most common element in a list
mostCommon :: (Ord a) => [a] -> a
mostCommon = head . maximumBy (comparing length) . group . sort

-- The function in question
consensus :: [Bool] -> [Action] -> IO [Action]
consensus [x] [action] = sequence [semiRandomAction x action]
consensus xs actions = do
  let xs' = oneOutSublists xs
      actions' = map (replicate $ length xs') actions
  replies <- mapM (uncurry $ consensus) (zip xs' actions')
  map mostCommon replies -- < The problem line

main = do
  let xs = [True, False, False]
      actions = [A, A, A]
  result <- consensus xs actions
  print result

ghc输出

➜  ~ stack ghc example.hs 
[1 of 1] Compiling Main             ( example.hs, example.o )

example.hs:29:3: error:
    • Couldn't match type ‘[]’ with ‘IO’
      Expected type: IO [Action]
        Actual type: [Action]
    • In a stmt of a 'do' block: map mostCommon replies
      In the expression:
        do let xs' = oneOutSublists xs
               actions' = map (replicate $ length xs') actions
           replies <- mapM (uncurry $ consensus) (zip xs' actions')
           map mostCommon replies
      In an equation for ‘consensus’:
          consensus xs actions
            = do let xs' = ...
                     ....
                 replies <- mapM (uncurry $ consensus) (zip xs' actions')
                 map mostCommon replies
   |
29 |   map mostCommon replies
   |   

最佳答案

consensus应该返回 IO [Action] 类型的值.这就是Expected type: IO [Action]意味着。

然而,map mostCommon replies[Action] 类型的表达式(因为 map 返回一个普通列表,没有 IO )。

I was under the impression that it was not possible remove the IO from a return value.

的确如此,这就是您收到类型错误的原因。 “无法删除 IO”不是基本属性,它只是来自标准库中可用操作的类型。

那么我们如何解决这个问题呢?

您的值类型为 IO [[Action]] , 即 mapM (uncurry $ consensus) (zip xs' actions') .您要应聘mostCommon到每个内部列表(在 IO 内的外部列表内)。

通过使用 <-do block ,您可以在本地从 IO a 中“提取”值:

replies <- mapM (uncurry $ consensus) (zip xs' actions')
-- replies :: [[Action]]

通过使用 map ,可以申请mostCommon到每个子列表:

map mostCommon replies :: [Action]

缺少的是您需要在 IO 中“重新包装”您的值制作 do block 通过类型检查(do block 中的每个单独语句必须具有相同的基本类型,在本例中为 IO ):

return (map mostCommon replies)

在这里return :: [Action] -> IO [Action] (或一般情况下:return :: (Monad m) => a -> m a)。

关于haskell - 返回类型丢失 IO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53314510/

相关文章:

list - 如何将列表列表与列表列表结合起来

haskell - 如何将Stackage安装为系统默认值?

haskell - Haskell中不同数据类型的字段标签之间的名称冲突

optimization - 优化 Haskell 文本处理

scala - 为什么 Scala 没有为每个 monad 定义返回/单元函数(与 Haskell 相比)?

haskell - 在 State Monad 中构建错误处理的最小 Haskell 示例

haskell - Haskell 中的 "Lazy IO"?

haskell - 是否可以删除此 DataKinds 支持的异构列表实现的 OverlappingInstances?

haskell - 尝试遍历森林 Haskell 编译错误

haskell - 使用 `handle` 产生的不明确的类型变量