Haskell从IO域获取值

时间:2018-09-01 06:40:23

标签: haskell io monads type-mismatch do-notation

看了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。在“世界”之间传递值是否有一条简单的经验法则?或者忽略类型标记只是我的坏选择吗?

2 个答案:

答案 0 :(得分:3)

关于do表示法的事情是,其中的每个单子动作值(在<-右边或在它们自己的行上)都必须属于同一 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]。纯值。

答案 1 :(得分: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绑定对其进行修复:

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