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