Haskell 从 IO 域获取值

Haskell get values from IO domain

读完 Haskell 书后,我有点困惑(或者我只是忘记了)如何从 IO 域中获取一个值,然后进入 'Haskell world' 来解析它,就像这样:

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

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

显然编译器会报错。 Couldn't match [] with IO。在 'worlds' 之间传递值是否有简单的经验法则,或者省略 typesigs 只是我的错?

关于 do 符号的事情是,其中的每个 monadic 动作值(那些在 <-s 右边的,或者在他们自己的行上的)必须属于 the相同 单子。这是

 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 的本质是在潜在不纯的 'effectful' 计算之间分层纯 'Haskell world' 计算。

所以我们已经在 Haskell 的纯净世界中,在 <- 的左侧。同样,inputs :: [String]。纯粹的价值。

get a value from the IO domain, into the 'Haskell world'

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

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

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

因此在 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