展开从IO(a)

问题描述:

过去两周我一直在学习Haksell,并决定在Hackerrank等地尝试挑战。这需要学习IO。我已经阅读了stackExchange上的很多答案,一般的要点是你不打开IO ......你只是在IO函数内部操作这些数据。如果我不允许将数据从主数据发送给他们,那么这就是所有纯函数的意义所在?下面是一些读取多少个测试用例的代码,然后为每个测试用例读取N个有序对。展开从IO(a)

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)]到validFunction。

+4

您无法将'IO a'变成'a'。你需要用'fmap validFunction'来获得'IO [(Int,Int)] - > IO Bool',然后使用它。一旦你执行了IO,你永远不会有一个没有显示IO正在执行的类型 - 按设计。 – chi

+0

是的,我明白从我读过的所有答案中。我似乎无法找到的是任何明确的示例,显示我需要的语法。这似乎都涉及停留在主内的代码。我找不到任何代码使用您建议的语法从do块调用“纯函数”。 –

+0

'rs'的类型是什么?如果它是'IO [(Int,Int)]',那么你需要'fmap validFunction rs',它的类型是'IO Bool'。 – Lee

首先,如果您在do中使用x <- act,那么您基本上有一个值。除非你做了非常可疑,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) 

后者是难读,但。但你写fooDodoTest如你想do

+0

很好的解释。可悲的是,在所有关于我做的事情中,我确实返回了validFunction rs,但缺少()或$让我了。我一直忘记它的正确联想。 –

+3

@TonyChamberlain'return'是一个函数,而不是关键字。这是人们必须记住的关键(赫)。 – Zeta