1

在阅读了 Haskell 书籍之后,我有点困惑(或者我只是忘记了)如何从 IO 域中获取一个值,进入“Haskell 世界”来解析它,如下所示:

fGetSeq = do
  input <- sequence [getLine, getLine, getLine]
  fTest input
  mapM_ print input

fTest =  map (read :: String -> Int)

显然编译器抱怨。Couldn't match [] with IO. 是否有一个简单的经验法则可以在“世界”之间传递值,或者省略类型符号只是我的坏事?

4

2 回答 2

3

关于do符号的问题是,其中的每个 monadic 动作值(在<-s 的右边,或在它们自己的行上)必须属于同一个monad。它是

 do {
      x <- ma ;          -- ma :: m a     x       :: a
      y <- mb ;          -- mb :: m b     y       :: b   ( with the same m! )
      return (foo x y)   --               foo x y :: c     return (foo x y) :: m c
    }                    --    :: m                  c

现在,因为sequence [getLine, getLine, getLine] :: IO [String],这意味着您的do块属于IO

但是,当您获得这些值时,您可以自行处理它们:

fGetSeq :: IO ()
fGetSeq = do
  inputs <- sequence [getLine, getLine, getLine]   -- inputs :: [String]
  let vals = fTest inputs
  mapM_ print vals

fTest :: [String] -> [Int]
fTest =  map (read :: String -> Int)

-- or just
fGetSeq1 = do
  inputs <- sequence [getLine, getLine, getLine]
  mapM_ print ( fTest inputs )

-- or
fGetSeq2 = do { vals <- fTest <$> sequence [getLine, getLine, getLine] ;
                mapM_ print vals }   -- vals :: [Int]

-- or even (with redundant parens for clarity)
fGetSeq3 = mapM_ print =<< ( fTest <$> sequence [getLine, getLine, getLine] )
    --   = mapM_ print . fTest =<< sequence [getLine, getLine, getLine]

Monad 的本质是纯粹的“Haskell 世界”计算在潜在不纯、“有效”计算之间的分层。

所以我们已经在纯粹的 Haskell 世界中,在它的左边<-。再次,inputs :: [String]。一个纯粹的价值。

于 2018-09-01T06:52:18.013 回答
1

从 IO 域中获取一个值,进入“Haskell 世界”

您使用绑定运算符:(>>=) :: Monad m => m a -> (a -> m b) -> m b

如果m = IO它看起来像:(>>=) :: IO a -> (a -> IO b) -> IO b

如您所见,具有类型的函数a -> IO b解决了a没有IO.

因此,在 IO monad 中给出一个值,例如getLine :: IO String

getInt :: IO Int
getInt = getLine >>= (\s -> return (read s))

在这里,s :: Stringread :: String -> Intreturn :: Int -> IO Int

您可以使用 do-block 重写它:

getInt :: IO Int
getInt = do
  s <- getLine
  return (read s)

或者使用执行此操作的标准库函数:

getInt :: IO Int
getInt = readLn

至于您的示例,您可以使用 let-binding 立即修复它:

foo :: IO ()
foo = do
  input <- sequence [getLine, getLine, getLine]
  let ints = bar input
  mapM_ print ints

bar :: [String] -> [Int]
bar = map read

或者您可以重组它以getInt按照上面的定义使用:

foo :: IO ()
foo = sequence [getInt, getInt, getInt] >>= mapM_ print
于 2018-09-01T08:15:27.033 回答