从IO(a)展开a

时间:2017-04-05 11:43:18

标签: haskell

过去两周我一直在学习Haksell,并决定在Hackerrank这样的地方尝试挑战。这需要学习IO。我已经在stackExchange上阅读了很多答案,而一般的要点是你没有打开IO ...你只是在IO函数中操作那些数据。那就是所有纯函数的重点是什么,如果我不允许从main发送数据给它们?下面是一些代码,它读取了多少个测试用例,然后每个测试用例读取N个有序对。

main = do
     test <- getLine
     replicateM (read test) doTest

doTest = do
    query<-getLine
    rs<-replicateM (read query) readPair
    return rs  -- just here to make the file compile

readPair :: IO (Int, Int)
readPair = do
   input <- getLine
   let a = words input in return (read (a!!0) :: Int, read (a!!1) ::Int)

此时我在rs里面有一个IO [(Int,Int)]。我想将这些数据发送到这个函数:

validFunction :: [(Int,Int)]->Bool
validFuntion [] = True
validFunction (x:[]) = True
validFunction (x:xs) = (not $ elem (snd x) (fmap snd xs))  && validFunction xs

但我似乎无法弄清楚如何做到这一点。有关如何使用我从用户那里读取的数据调用此函数的任何帮助或建议将不胜感激。或者,如果我从错误的角度出发,指出我应该做的事情也会有效。

编辑:通过阅读这里的许多其他问题,我得到了一般的想法,一旦你的IO卡在那里。但我似乎无法找到的是使用IO数据调用纯函数并获取IO数据的语法。我尝试了以下一些方法:

fmap validFunction [rs] :: IO Bool  -- tried it with just rs without [] as well 
mapM validFunction [rs] :: IO Bool
validFunction rs :: IO Bool

我能够让这个工作:

 putStrLn . f . validFunction $ rs

虽然我仍然不清楚为什么这会让你将IO [(Int,Int)]传递给validFunction。

1 个答案:

答案 0 :(得分:7)

首先,如果您在x <- act中使用do,则基本上有一个值。除非您做了非常可疑的事情,x不是IO something,而是something:所以使用

完全没问题
foo :: Int -> Char
foo = …

bar :: IO Int
bar = …

fooDo :: IO Char
fooDo = do
   number <- bar
   return (foo number) -- apply foo directly on number

但是,IOFunctor的一个实例,因此我们可以使用fmap 解除 foo

liftedFoo :: IO Int -> IO Char
liftedFoo = fmap foo

所以我们可以像这样编写fooDo

fooDo = fmap foo readLn

虽然它的名字现在有误导性,但它仍然和以前一样。但是,让我们把这个命名巫毒放在一边,你会如何解决这个问题?好吧,您的doTest具有正确的类型:

doTest :: IO [(Int, Int)]
doTest = do
    query  <- getLine
    rs     <- replicateM (read query) readPair
    return rs

所以缺少的是调用validFunction。我们可以像fooDo

那样做
doTest :: IO Bool
doTest = do
    query  <- getLine
    rs     <- replicateM (read query) readPair
    return (validFunction rs)
--         ^^^^^^^^^^^^^^^^^^
--         no IO  inside here
--  ^^^^^^ 
--   back 
--  to  IO

或者我们可以fmap超过IO的其他replicateM (read query) readPair值:

doTest :: IO Bool
doTest = do
    query  <- getLine
    fmap validFunction (replicateM (read query) readPair)

后者更难以阅读。但您可以根据需要fooDo编写 doTest do