1

过去两周我一直在学习 Haskell,并决定在 HackerRank 等地方尝试挑战。这需要学习IO。我在 StackExchange 上阅读了很多答案,一般要点是您不要 unwrap ,您只需在函数IO a内操作该数据。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)

在这一点上,我有一个IO [(Int, Int)]内部rs。我想将该数据发送到此函数:

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)]to validFunction

4

1 回答 1

7

首先,如果你使用x <- actin do,你本质上是有价值的。除非你做了一些非常可疑的事情,否则x不是 a IO something,而是 a something: 所以使用它是完全可以的

foo :: Int -> Char
foo = …

bar :: IO Int
bar = …

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

但是,IO是 的一个实例Functor,所以我们可以使用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

于 2017-04-05T12:25:31.143 回答